參考:https://github.com/dmendel/bindata/wiki
BinData提供了一種聲明性方式來讀取和寫入結(jié)構(gòu)化二進(jìn)制數(shù)據(jù)。
這意味著程序員指定二進(jìn)制數(shù)據(jù)的格式,BinData設(shè)計(jì)出如何以這種格式讀寫數(shù)據(jù)。 這是一個更容易(和更可讀)的替代ruby的#pack和#unpack方法。
導(dǎo)航
安裝
您可以通過rubygems安裝BinData。
gem install bindata
或者簽出代碼:
git clone https://github.com/dmendel/bindata.git
概述
BinData聲明很容易閱讀。 這里有一個例子。
class MyFancyFormat < BinData::Record
stringz :comment
uint8 :len
array :data, :type => :int32be, :initial_length => :len
end
這種花哨的格式描述以下數(shù)據(jù)集合:
:comment:一個零終止的字符串
:len:無符號8位整數(shù)
:data:無符號32位高端整數(shù)序列。 整數(shù)的數(shù)量由以下值表示:len
BinData聲明與英語描述緊密匹配。 將上述聲明與等效的#unpack代碼進(jìn)行比較,以讀取這樣的數(shù)據(jù)記錄。
def read_fancy_format(io)
comment, len, rest = io.read.unpack("ZCa")
data = rest.unpack("N#{len}")
{:comment => comment, :len => len, :data => *data}
end
BinData聲明清楚地顯示了記錄的結(jié)構(gòu)。 #unpack代碼使此結(jié)構(gòu)不透明。
BinData的一般用法是將數(shù)據(jù)的結(jié)構(gòu)化集合聲明為用戶定義的記錄。 該記錄可以被實(shí)例化,讀取,寫入和操縱,而用戶不必關(guān)心基本的二進(jìn)制數(shù)據(jù)表示。
記錄
BinData記錄聲明的一般格式是包含一個或多個字段的類。
class MyName < BinData::Record
type field_name, :param1 => "foo", :param2 => bar, ...
...
end
type :是提供的類型的名稱(例如uint32be,string,array)或用戶定義的類型。 對于用戶定義的類型,類名稱從CamelCase轉(zhuǎn)換為lowercased underscore_style
field_name:是您可以訪問該字段的名稱。 使用符號作為名稱。 如果省略名稱,則此特定字段為匿名。 匿名字段仍在讀取和寫入,但不會出現(xiàn)在#snapshot中。
每個字段可以具有用于如何處理數(shù)據(jù)的可選參數(shù)。 參數(shù)作為帶有符號的哈希鍵傳遞。 參數(shù)被設(shè)計(jì)為懶惰評估,可能多次。 這意味著任何參數(shù)值都不能有副作用。
以下是參數(shù)的合法值的一些示例。
:param => 5
:param => lambda {foo + 2}
:param =>:bar
最簡單的情況是值為字面值,例如5。
如果值不是文字,它應(yīng)該是一個lambda。 將在父級的上下文中評估lambda。 在這種情況下,父項(xiàng)是MyName的實(shí)例。
如果值是一個符號,它將作為包含符號值的lambda的語法糖。 例如:param =>:bar等效于:param => lambda {bar}
指定默認(rèn)字節(jié)序
數(shù)字類型的字節(jié)順序必須明確定義,以便生成的代碼獨(dú)立于架構(gòu)。 但是,為每個數(shù)字字段顯式指定endian可能導(dǎo)致難以閱讀的膨脹聲明。
class A < BinData::Record
int16be :a
int32be :b
int16le :c # <-- Note little endian!
int32be :d
float_be :e
array :f, :type => :uint32be
end
endian關(guān)鍵字可用于設(shè)置默認(rèn)字節(jié)序。 這使得聲明更容易閱讀。 不使用默認(rèn)邊框的任何數(shù)字字段可以顯式覆蓋它。
class A < BinData::Record
endian :big
int16 :a
int32 :b
int16le :c # <-- Note how this little endian now stands out
int32 :d
float :e
array :f, :type => :uint32
end
通過上述示例可以看出清晰度的增加。 endian關(guān)鍵字將級聯(lián)到嵌套類型,如上例中的數(shù)組所示。
基本類型
Endian with custom types
endian關(guān)鍵字也可以用于標(biāo)識具有字節(jié)順序的自定義類型。 為此,自定義類型的類名必須以Le結(jié)尾,對于小尾數(shù),Be為大尾。
class CoordLe < BinData::Record
endian :little
int16 :x
int16 :y
end
class CoordBe < BinData::Record
endian :big
int16 :x
int16 :y
end
class Rectangle < BinData::Record
endian :little
coord :upper_left # <-- Here CoordLe is automatically
coord :lower_right # <-- assumed
end
聲明兩個:big和:little endian自定義類型
復(fù)合類型
常見操作
高級主題
高級I / O
常問問題
如何使用字符串編碼與BinData?
備擇方案
這一部分純屬歷史。 BinData的所有替代方法不再被積極維護(hù)。
BinData有幾種替代方法。下面是BinData和其替代品之間的比較。
簡短的形式是,BinData是大多數(shù)情況下的最佳選擇。它是所有替代品中最全面的。它也可以說是最可讀和最簡單的方法來解析和寫入二進(jìn)制數(shù)據(jù)。
BitStruct
BitStruct是所有替代品中最完整的。它是聲明性的,并支持大多數(shù)與BinData相同的原始類型。它的特殊功能是報(bào)告生成的自我記錄功能。 BitStruct的設(shè)計(jì)選擇是偏好速度超過靈活性。
BitStruct的主要限制是它不支持可變長度字段和依賴字段。這使得它很難處理任何非平凡的文件格式。
如果速度很重要,你只處理簡單的二進(jìn)制數(shù)據(jù)類型,那么BitStruct可能是一個不錯的選擇。對于非平凡數(shù)據(jù)類型,BinData是更好的選擇。
二進(jìn)制稀疏
BinaryParse是一個聲明式樣的打包器/解包器。它提供了與Ruby的#pack相同的原語,增加了日期和時間。像BitStruct,它不提供依賴或可變長度字段。
BinStruct
BinStruct是解包二進(jìn)制數(shù)據(jù)的命令式方法。它提供了一些聲明性語法糖。它支持最常見的基本類型,以及任意長度的位域。
它的主要焦點(diǎn)是作為一個二進(jìn)制模糊器,而不是一個通用的解碼/編碼庫。
可包裝
Packable使它更好地使用Ruby的#pack和#unpack方法。而不是必須記住,例如“n”是打包16位大端整數(shù)的代碼,可壓縮提供了許多方便的快捷方式。在“n”的情況下,可以使用{:bytes => 2,:endian =>:big}。
使用Packable提高了#pack和#unpack方法的可讀性,但顯式調(diào)用#pack和#unpack并不像聲明方法那樣可讀。
Bitpack
Bitpack提供從八位字節(jié)流中提取任意位長的大端整數(shù)的方法。
提取代碼是用C編寫的,所以如果速度很重要,位操作是所有你需要的功能,那么這可能是一個替代方法。這一節(jié)純粹是歷史的。 BinData的所有替代方法不再被積極維護(hù)。
BinData有幾種替代方法。下面是BinData和其替代品之間的比較。
簡短的形式是BinData是大多數(shù)情況下的最佳選擇。它是所有替代品中最全面的。它也可以說是最可讀和最簡單的方法來解析和寫入二進(jìn)制數(shù)據(jù)。
BitStruct
BitStruct是所有替代品中最完整的。它是聲明性的,并支持大多數(shù)與BinData相同的原始類型。它的特殊功能是報(bào)告生成的自我記錄功能。 BitStruct的設(shè)計(jì)選擇是偏好速度超過靈活性。
BitStruct的主要限制是它不支持可變長度字段和依賴字段。這使得它很難處理任何非平凡的文件格式。
如果速度很重要,你只處理簡單的二進(jìn)制數(shù)據(jù)類型,那么BitStruct可能是一個不錯的選擇。對于非平凡數(shù)據(jù)類型,BinData是更好的選擇。
二進(jìn)制稀疏
BinaryParse是一個聲明式樣的打包器/解包器。它提供了與Ruby的#pack相同的原語,增加了日期和時間。像BitStruct,它不提供依賴或可變長度字段。
BinStruct
BinStruct是解包二進(jìn)制數(shù)據(jù)的命令式方法。它提供了一些聲明性語法糖。它支持最常見的基本類型,以及任意長度的位域。
它的主要焦點(diǎn)是作為一個二進(jìn)制模糊器,而不是一個通用的解碼/編碼庫。
可包裝
Packable使它更好地使用Ruby的#pack和#unpack方法。而不是必須記住,例如“n”是打包16位大端整數(shù)的代碼,可壓縮提供了許多方便的快捷方式。在“n”的情況下,可以使用{:bytes => 2,:endian =>:big}。
使用Packable提高了#pack和#unpack方法的可讀性,但顯式調(diào)用#pack和#unpack并不像聲明方法那樣可讀。
Bitpack
Bitpack提供從八位字節(jié)流中提取任意位長的大端整數(shù)的方法。
提取代碼用C編寫,因此如果速度很重要,位操作是所有你需要的功能,那么這可能是一個替代。
它是什么?
你有沒有發(fā)現(xiàn)自己寫這樣的代碼?
io = File.open(...)
len = io.read(2).unpack("v")[0]
name = io.read(len)
width, height = io.read(8).unpack("VV")
puts "Rectangle #{name} is #{width} x #{height}"
這是丑陋,違反DRY,感覺像你在寫Perl,而不是Ruby。
有一個更好的方法。
class Rectangle < BinData::Record
endian :little
uint16 :len
string :name, :read_length => :len
uint32 :width
uint32 :height
end
io = File.open(...)
r = Rectangle.read(io)
puts "Rectangle #{r.name} is #{r.width} x #{r.height}"
BinData使您可以輕松地指定要操作的數(shù)據(jù)的結(jié)構(gòu)。
它支持在結(jié)構(gòu)化二進(jìn)制數(shù)據(jù)中找到的所有常見數(shù)據(jù)類型。 支持依賴和可變長度字段。BinData使您可以輕松地指定要操作的數(shù)據(jù)的結(jié)構(gòu)。
它支持在結(jié)構(gòu)化二進(jìn)制數(shù)據(jù)中找到的所有常見數(shù)據(jù)類型。 支持依賴和可變長度字段。