參考:https://github.com/dmendel/bindata/wiki
BinData提供了一種聲明性方式來讀取和寫入結構化二進制數據。
這意味著程序員指定二進制數據的格式为肮,BinData設計出如何以這種格式讀寫數據往踢。 這是一個更容易(和更可讀)的替代ruby的#pack和#unpack方法突勇。
導航
安裝
您可以通過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
這種花哨的格式描述以下數據集合:
:comment:一個零終止的字符串
:len:無符號8位整數
:data:無符號32位高端整數序列她倘。 整數的數量由以下值表示:len
BinData聲明與英語描述緊密匹配。 將上述聲明與等效的#unpack代碼進行比較作箍,以讀取這樣的數據記錄硬梁。
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聲明清楚地顯示了記錄的結構。 #unpack代碼使此結構不透明胞得。
BinData的一般用法是將數據的結構化集合聲明為用戶定義的記錄荧止。 該記錄可以被實例化,讀取阶剑,寫入和操縱跃巡,而用戶不必關心基本的二進制數據表示。
記錄
BinData記錄聲明的一般格式是包含一個或多個字段的類牧愁。
class MyName < BinData::Record
type field_name, :param1 => "foo", :param2 => bar, ...
...
end
type :是提供的類型的名稱(例如uint32be素邪,string,array)或用戶定義的類型猪半。 對于用戶定義的類型兔朦,類名稱從CamelCase轉換為lowercased underscore_style
field_name:是您可以訪問該字段的名稱。 使用符號作為名稱磨确。 如果省略名稱烘绽,則此特定字段為匿名。 匿名字段仍在讀取和寫入俐填,但不會出現在#snapshot中。
每個字段可以具有用于如何處理數據的可選參數翔忽。 參數作為帶有符號的哈希鍵傳遞英融。 參數被設計為懶惰評估,可能多次歇式。 這意味著任何參數值都不能有副作用驶悟。
以下是參數的合法值的一些示例。
:param => 5
:param => lambda {foo + 2}
:param =>:bar
最簡單的情況是值為字面值材失,例如5痕鳍。
如果值不是文字,它應該是一個lambda龙巨。 將在父級的上下文中評估lambda笼呆。 在這種情況下,父項是MyName的實例旨别。
如果值是一個符號诗赌,它將作為包含符號值的lambda的語法糖。 例如:param =>:bar等效于:param => lambda {bar}
指定默認字節(jié)序
數字類型的字節(jié)順序必須明確定義秸弛,以便生成的代碼獨立于架構铭若。 但是洪碳,為每個數字字段顯式指定endian可能導致難以閱讀的膨脹聲明。
class A < BinData::Record
int16be :a
int32be :b
int16le :c # <-- Note little endian!
int32be :d
float_be :e
array :f, :type => :uint32be
end
endian關鍵字可用于設置默認字節(jié)序叼屠。 這使得聲明更容易閱讀瞳腌。 不使用默認邊框的任何數字字段可以顯式覆蓋它。
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關鍵字將級聯到嵌套類型嫂侍,如上例中的數組所示。
基本類型
Endian with custom types
endian關鍵字也可以用于標識具有字節(jié)順序的自定義類型冷离。 為此吵冒,自定義類型的類名必須以Le結尾,對于小尾數西剥,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自定義類型
復合類型
常見操作
高級主題
高級I / O
常問問題
如何使用字符串編碼與BinData?
備擇方案
這一部分純屬歷史瞭空。 BinData的所有替代方法不再被積極維護揪阿。
BinData有幾種替代方法。下面是BinData和其替代品之間的比較咆畏。
簡短的形式是南捂,BinData是大多數情況下的最佳選擇。它是所有替代品中最全面的旧找。它也可以說是最可讀和最簡單的方法來解析和寫入二進制數據溺健。
BitStruct
BitStruct是所有替代品中最完整的。它是聲明性的钮蛛,并支持大多數與BinData相同的原始類型鞭缭。它的特殊功能是報告生成的自我記錄功能。 BitStruct的設計選擇是偏好速度超過靈活性魏颓。
BitStruct的主要限制是它不支持可變長度字段和依賴字段岭辣。這使得它很難處理任何非平凡的文件格式。
如果速度很重要甸饱,你只處理簡單的二進制數據類型沦童,那么BitStruct可能是一個不錯的選擇。對于非平凡數據類型叹话,BinData是更好的選擇偷遗。
二進制稀疏
BinaryParse是一個聲明式樣的打包器/解包器。它提供了與Ruby的#pack相同的原語渣刷,增加了日期和時間鹦肿。像BitStruct,它不提供依賴或可變長度字段辅柴。
BinStruct
BinStruct是解包二進制數據的命令式方法箩溃。它提供了一些聲明性語法糖瞭吃。它支持最常見的基本類型,以及任意長度的位域涣旨。
它的主要焦點是作為一個二進制模糊器歪架,而不是一個通用的解碼/編碼庫。
可包裝
Packable使它更好地使用Ruby的#pack和#unpack方法霹陡。而不是必須記住和蚪,例如“n”是打包16位大端整數的代碼,可壓縮提供了許多方便的快捷方式烹棉。在“n”的情況下攒霹,可以使用{:bytes => 2,:endian =>:big}浆洗。
使用Packable提高了#pack和#unpack方法的可讀性催束,但顯式調用#pack和#unpack并不像聲明方法那樣可讀。
Bitpack
Bitpack提供從八位字節(jié)流中提取任意位長的大端整數的方法伏社。
提取代碼是用C編寫的抠刺,所以如果速度很重要,位操作是所有你需要的功能摘昌,那么這可能是一個替代方法速妖。這一節(jié)純粹是歷史的。 BinData的所有替代方法不再被積極維護聪黎。
BinData有幾種替代方法罕容。下面是BinData和其替代品之間的比較。
簡短的形式是BinData是大多數情況下的最佳選擇稿饰。它是所有替代品中最全面的杀赢。它也可以說是最可讀和最簡單的方法來解析和寫入二進制數據。
BitStruct
BitStruct是所有替代品中最完整的湘纵。它是聲明性的,并支持大多數與BinData相同的原始類型滤淳。它的特殊功能是報告生成的自我記錄功能梧喷。 BitStruct的設計選擇是偏好速度超過靈活性。
BitStruct的主要限制是它不支持可變長度字段和依賴字段脖咐。這使得它很難處理任何非平凡的文件格式铺敌。
如果速度很重要,你只處理簡單的二進制數據類型屁擅,那么BitStruct可能是一個不錯的選擇偿凭。對于非平凡數據類型,BinData是更好的選擇派歌。
二進制稀疏
BinaryParse是一個聲明式樣的打包器/解包器弯囊。它提供了與Ruby的#pack相同的原語痰哨,增加了日期和時間。像BitStruct匾嘱,它不提供依賴或可變長度字段斤斧。
BinStruct
BinStruct是解包二進制數據的命令式方法。它提供了一些聲明性語法糖霎烙。它支持最常見的基本類型撬讽,以及任意長度的位域。
它的主要焦點是作為一個二進制模糊器悬垃,而不是一個通用的解碼/編碼庫游昼。
可包裝
Packable使它更好地使用Ruby的#pack和#unpack方法。而不是必須記住尝蠕,例如“n”是打包16位大端整數的代碼烘豌,可壓縮提供了許多方便的快捷方式。在“n”的情況下趟佃,可以使用{:bytes => 2扇谣,:endian =>:big}。
使用Packable提高了#pack和#unpack方法的可讀性闲昭,但顯式調用#pack和#unpack并不像聲明方法那樣可讀罐寨。
Bitpack
Bitpack提供從八位字節(jié)流中提取任意位長的大端整數的方法。
提取代碼用C編寫序矩,因此如果速度很重要鸯绿,位操作是所有你需要的功能,那么這可能是一個替代簸淀。
它是什么瓶蝴?
你有沒有發(fā)現自己寫這樣的代碼?
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使您可以輕松地指定要操作的數據的結構。
它支持在結構化二進制數據中找到的所有常見數據類型贾富。 支持依賴和可變長度字段歉眷。BinData使您可以輕松地指定要操作的數據的結構。
它支持在結構化二進制數據中找到的所有常見數據類型颤枪。 支持依賴和可變長度字段汗捡。