二进制型(binary)是一种数据结构,当二进制型里的位数都会是8的整数倍时,对应一个字节串。当位数不是8的整数倍,则称这段数据为位串(bitstring)。
二进制型的编写和打印形式是双小于号与双大于号之间的一列整数或字符串:
1> <<19,88,20>>.
<<19,88,20>>
2> <<"hello">>.
<<"hello">>
3> <<49,50,51>>.
<<"123">>
4> <<99,97,116>>.
<<"cat">>
在二进制型里使用整数时,它们必须属于0至255这个范围。
二进制型<<"cat">>是<<99,97,116>>的简写形式,这个二进制型是由字符串里这些字符的ASCII编码组成的。
和字符串类似,如果某个二进制型的内容是可打印的字符串,shell就会将这个二进制型打印成字符串,否则就打印成一列整数。
可以用内置函数和位语法来构建二进制型或提取它里面的元素。
1. 内置函数
list_to_binary(L) -> B
list_to_binary返回一个二进制型,它是通过把io列表(iolist)L里的所有元素压扁后形成的(压扁的意思是移除列表里所有的括号)。io列表本身是循环定义的,它是指一个列表所包含的元素是0…255的整数、二进制型或者其他io列表。
5> list_to_binary([999,123]). %% 999超出范围0~255
** exception error: bad argument
in function list_to_binary/1
called as list_to_binary([999,123])
6> list_to_binary([<<"abc">>, 123, <<1,2,3>>]).
<<97,98,99,123,1,2,3>>
split_binary(Bin, Pos) -> {Bin1, Bin2}
这个函数在Pos处把二进制型Bin一分为二。
7> split_binary(<<1,2,3,4,5,6,7,8>>, 3).
{<<1,2,3>>,<<4,5,6,7,8>>}
-
term_to_binary(Term) -> Bin
把任何Erlang数据类型转换成一个二进制型。 -
binary_to_term(Bin) -> Term
term_to_binary的逆操作。
8> term_to_binary({abc, [1,2,3]}).
<<131,104,2,100,0,3,97,98,99,107,0,3,1,2,3>>
9> binary_to_term(<<131,104,2,100,0,3,97,98,99,107,0,3,1,2,3>>).
{abc,[1,2,3]}
byte_size(Bin) -> Size
10> byte_size(<<1,2,3>>).
3
11> byte_size(<<>>).
0
2. 位语法
位语法是一种表示法,用于从二进制数据里提取或加入单独的位或者位串。
它们的形式如下:
<<>>
<<E1, E2, ..., En>>
每个Ei元素都标识出二进制型或位串里的一个片段。单个Ei元素可以有4种形式。
Ei = Value |
Value:Size |
Value/TypeSpecifierList |
Value:Size/TypeSpecifierList
如果表达式的总位数是8的整数倍,就会构建一个二进制型,否则构建一个位串。
构建二进制型时,Value必须是已绑定变量、字符串,或是能得出整数、浮点数或二进制型的表达式。用于模式匹配操作时,Value可以是绑定或未绑定的变量、整数、字符串、浮点数或二进制型。
Size的值指明了片段的大小。它的默认值取决于不同的数据类型,对整数来说是8,浮点数则是64,如果是二进制型就是该二进制型的大小。在模式匹配里,默认值只对最后那个元素有效。如果未指定片段的大小,就会采用默认值。
TypeSpecifierList(类型指定列表)是一个用连字符分隔的列表,形式为End-Sign-Type-Unit。前面这些项中的任何一个都可以被省略,各个项也可以按任意顺序排列。如果省略了某一项,系统就会使用它的默认值。
End可以是big|little|native
它指定机器的字节顺序。native是指在运行时根据机器的CPU来确定。默认值是big,也就是网络字节顺序(network byte order)。
12> {<<16#12345678:32/big>>,<<16#12345678:32/little>>,<<16#12345678:32/native>>,<<16#12345678:32>>}. %% 16# 表示十六进制
{<<18,52,86,120>>,
<<120,86,52,18>>,
<<120,86,52,18>>,
<<18,52,86,120>>}
-
sign可以是signed|unsigned
这个参数只用于模式匹配。默认值是unsigned。 -
Type可以是integer|float|binary|bitstring|bits|utf8|utf16|utf32
默认值是integer。 -
Unit的写法是unit:1|2|...|256
integer、float和bitstring的Unit默认值是1,binary则是8。utf8、utf16和utf32类型无需提供值。
13> <<49:8>>.
<<"1">>
14> <<49:8/unit:1>>.
<<"1">>
15> <<49:8/unit:2>>.
<<0,49>>
16> <<49:7>>.
<<49:7>>
17> <<49:7/unit:1>>.
<<49:7>>
18> <<49:7/unit:2>>.
<<0,49:6>>
一个片段的总长度是Size x Unit``bit。binary类型的片段长度必须是8的整数倍。
3. 位推导
位推导和二进制型的关系就像列表推导和列表的关系一样。列表推导遍历列表并返回列表。位推导遍历二进制型并生成列表或二进制型。
19> B = <<16#5f>>.
<<"_">> %% 16#5f是一个十六进制的常量。shell把它打印成了<<"_">>,因为16#5f是_字符的ASCII编码。
20> [X || <<X:1>> <= B]. %% <<<X:1>>是一个模式,代表1位。
[0,1,0,1,1,1,1,1]
21> [X || <<X:2>> <= B].
[1,1,3,3]
22> << <<X>> || <<X:1>> <= B >>.
<<0,1,0,1,1,1,1,1>>
23> [X || <<X:1>> <- B]. %% 注意是 <= 而不是 <-
** exception error: bad generator <<"_">>
20与22的区别在于20构建了一个包含这些位的列表,而22构建了一个二进制型。
4. 实例
- 编写一个函数来反转某个二进制型里的字节顺序。
reverse_bitstring_by_byte(BitString) ->
ByteList = [Byte || <<Byte:8>> <= BitString],
ReverseByteList = lists:reverse(ByteList),
ReverseBitString = list_to_binary(ReverseByteList),
ReverseBitString.
- 编写一个函数来反转某个二进制型所包含的位。
reverse_bitstring_by_bit(BitString) ->
BitList = [Bit || <<Bit:1>> <= BitString],
ReverseBitList = lists:reverse(BitList),
ReverseBitString = list_to_binary(ReverseBitList),
ReverseBitString1 = << <<Bit:1>> || <<Bit:8>> <= ReverseBitString>>,
ReverseBitString1.
注:本博客为通过《Erlang程序设计 第二版》学习Erlang时所做的笔记。学习更详细的内容,建议直接阅读《Erlang程序设计 第二版》。
本文介绍了Erlang中的二进制数据结构,包括二进制型与位串的概念,以及如何使用内置函数和位语法进行操作。重点讲述了如何构建、拆分二进制,以及通过位推导进行位操作。文中还提供了实例,如反转二进制字节顺序和位顺序,帮助理解Erlang中二进制的处理方式。
491

被折叠的 条评论
为什么被折叠?



