Erlang:二进制文件和位串


Erlang拥有高效操作字节和位序列的语言支持,提供了访问这些流的低级接口,同时保持了运行在虚拟机上的语言的舒适性。

因此,我在学习和编写Erlang编程书籍时,编写了一些探索性的测试,这绝对是一个推荐的来源,因为它从Erlang中提取了在其他语言中找不到的所有位(双关语),同时快速了解了如何编写for循环(实际上是一个list comprehension或者map operation)。

二进制文件

二进制表示Erlang中有序的字节序列。将Erlang数据结构打包成二进制文件以便通过网络发送是很容易的,我尝试用一个原子来实现这一点:

binary_representation_test() ->
  Bin = term_to_binary(a),
  ?assertEqual(<<131, 100, 0, 1, 97>>, Bin).

这是一个40位的序列,组织成5个字节。<<>语法是直接表达字节或位序列的习惯,如果您什么也不说,每个逗号分隔的值将被视为一个字节长。

您可以使用您期望的应用编程接口将它们转换回Erlang数据结构:

binary_conversions_test() ->
  Bin = term_to_binary(a),
  ?assertEqual(a, binary_to_term(Bin)).

我不知道Erlang在这里使用的格式,不用说,您不应该依赖这个实现细节,而应该只使用原语进行转换。

我们当然不限于原子:我已经用更复杂的嵌套数据结构测试了这种序列化机制。

binary_complex_conversions_test() ->
  Bin = term_to_binary({a, 42, {b, c}}),
  ?assertEqual({a, 42, {b, c}}, binary_to_term(Bin)).

让我们构建一个RGB三元组,用一个字节表示每个颜色分量,得到一个24位通道:

bit_building_test() ->
  G=6*16+6,
  B=9*16+9,
  Bin = <<0, G, B>>,
  ?assertEqual([0, G, B], binary_to_list(Bin)).

在这种情况下,将二进制文件分割成小于单个字节的段是没有用的。大多数高级编程都是如此。

因此,我们甚至可以对二进制文件中包含的字节进行模式匹配,只要它们是预先确定的量:

bit_pattern_matching_test() ->
  G=6*16+6,
  B=9*16+9,
  Bin = <<0, G, B>>,
  <<0, G, Blue>> = Bin,
  ?assertEqual(B, Blue).

位串

虽然二进制是表示字节序列的Erlang术语,但是位是以位串的形式组织的(就我所能操作的而言,它们实际上是相同的结构)。

当你在IP、UDP或TCP级别工作时,效率是非常重要的,并且可以直接从位串中提取单个位(或N位序列)。在另一种语言中,比如C或Java,你必须自己对字节进行抽象编码才能在位级别工作(使用位掩码)。

为了向您展示如何在位级别工作,让我们构建一个字符(由两个不同的4位序列组合而成的8位)。在ASCII码中,a是0x65,所以用两个4位序列来看是0100 0001:

bin_types_test() ->
  ?assertEqual(<<"A">>, <<4:4, 1:4>>).

使用:4后缀,我们告诉Erlang将表达式表示为长度为4的位串。

让我们做一些稍微复杂一点的事情:这些结构上的模式匹配。

bin_pattern_matching_with_types_test() ->
  Bin = <<"Answer", 42, "ok">>,
  <<"Answer", Int, Result/binary>> = Bin,
  ?assertEqual(42, Int),
  ?assertEqual(<<"ok">>, Result).

我们匹配的第一个模式是固定值“答案”;没问题。

第二种模式是变量,我们称之为Int;默认情况下,新变量将匹配8位长序列,这是最常见的类型(整数值)。

我们使用的第三种模式只是提取其余的二进制形式的Bin。由于数据包和数据段通常有一个固定长度的报头和一个可变的有效载荷,所以通常用这个表达式来提取它。

结论

Erlang的用例中确实包含了电池:低延迟通信网关和分布式系统。该语言本身混合了更高级的功能,如映射和过滤,并有可能在较低的级别分割流。

在其他语言中,您必须自己编写一个解析器,而Erlang允许以声明的方式编写二进制消息的内容,然后可以用来提取有趣的部分。通过用语言而不是用额外的库来实现这一点,Erlang也为优化打开了大门。

查看这些示例中使用的所有代码from GitHub