BinData - 在Ruby中解析二进制数据

参考: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}
指定默认字节序
数字类型的字节顺序必须明确定义,以便生成的代码独立于架构。 但是,为每个数字字段显式指定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关键字可用于设置默认字节序。 这使得声明更容易阅读。 不使用默认边框的任何数字字段可以显式覆盖它。
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关键字也可以用于标识具有字节顺序的自定义类型。 为此,自定义类型的类名必须以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提供从八位字节流中提取任意位长的大端整数的方法。

提取代码是用C编写的,所以如果速度很重要,位操作是所有你需要的功能,那么这可能是一个替代方法。这一节纯粹是历史的。 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提供从八位字节流中提取任意位长的大端整数的方法。

提取代码用C编写,因此如果速度很重要,位操作是所有你需要的功能,那么这可能是一个替代。
它是什么?
你有没有发现自己写这样的代码?
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使您可以轻松地指定要操作的数据的结构。

它支持在结构化二进制数据中找到的所有常见数据类型。 支持依赖和可变长度字段。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • about 这篇文章是Python2 的官方文档 7.3. struct — Interpret strings ...
    庞贝船长阅读 6,233评论 1 3
  • 由于工程项目中拟采用一种简便高效的数据交换格式,百度了一下发现除了采用 xml、JSON 还有 ProtoBuf(...
    黄海佳阅读 48,503评论 1 23
  • 1. 和朋友一起吃饭,餐厅很漂亮。心情很好,聊正事,也开玩笑。 不和谐的声音是这时候传过来的。“不是说让你们别点饮...
    言君阅读 642评论 0 51
  • 讨论的目标是为了让自己更明白 争论的目标是为了彻底说服对方 争论的冲动常常来自于自己的弱小,不是人微言轻,而是人微易怒
    格鲁特的日记阅读 1,770评论 0 0