Ruby で構造体もどき 続き
BinData と比較するためにコードを作成。
約1Mのモデルデータを読み込むコードです。BinData を使ったほうは2.5秒かかりました。自前の unpack ラッパーは約0.07秒。(PCスペックに左右されるので参考程度)
BinData は柔軟な記述ができる代わりに、いちいち数バイトずつ読み込んでるので死ぬほど遅いです。Ruby の場合(1.9.x限定かも)、ファイルを少しずつ読むと極端に速度が遅くなるという現象(ある程度改善されたようですが)があるので、最初に全てのデータを読み込んだほうが劇的に速度があがります。
さらに File.read する場合にファイルサイズを指定するとさらに読み込み速度が上がる(バイナリモード用?)ので、File.read(file_name, File.size(file_name)) とやったほうが良いです。
(追記)
StringIO を使って最初に全て読み込んでから BinData に食わせてみたところ、1.2秒までタイムが短縮しました。半分以下に。やっぱりファイルシークさせちゃダメですね。
でもやっぱりまだまだ遅いので、実用にはきびしい感じ(小さいファイルならまったく問題はありませんけど)
# BinData を使用した場合 require "bindata" class PMD < BinData::Record class Header < BinData::Record endian :little string :magic, :length => 3 float :version string :model_name, :length => 20 string :comment, :length => 256 uint32 :vert_count end class Vector < BinData::Record endian :little float :x float :y float :z end class Vertex < BinData::Record endian :little vector :pos vector :normal_vec float :u float :v array :bone_num, :type => :uint16, :initial_length => 2 uint8 :bone_weight uint8 :edge_flag end endian :little header :header array :vertex, :type => :vertex, :initial_length => ->{ header.vert_count } end pmd = PMD.new pmd.read(File.open("normal.pmd")) puts pmd.header.magic puts pmd.header.version puts pmd.header.model_name.unpack("Z*") puts pmd.header.comment.unpack("Z*") puts pmd.header.vert_count puts pmd.vertex[0]
class PMD # 〜略〜 def test bin = BinStruct::Stream.new("normal.pmd") header = bin.read(Header) puts header.magic puts header.version puts header.model_name puts header.comment puts vert_count = header.vert_count t_vertex = [] # 頂点を全て読み込むコードを追加 vert_count.times do t_vertex << bin.read(TVertex) end puts t_vertex[0].x puts t_vertex[0].y puts t_vertex[0].z puts t_vertex[0].nx puts t_vertex[0].ny puts t_vertex[0].nz puts t_vertex[0].u puts t_vertex[0].v puts t_vertex[0].bone_num_1 puts t_vertex[0].bone_num_2 puts t_vertex[0].bone_weight puts t_vertex[0].edge_flag end end