Erlang 二进制数据:<<>> 语法
Erlang 使用 <<>> 语法创建和操作二进制数据。这种语法让你能精确控制字节、位字段和数据编码,是处理网络协议、文件格式或加密数据的核心工具。
创建基本二进制
- 输入
<<1, 2, 3>>创建一个包含三个字节的二进制。每个数字默认占 8 位(1 字节),值必须在0到255范围内。 - 输入
<<256>>会报错,因为256超出单字节范围。若需更大数值,需显式指定位宽。 - 使用
<<1000:32>>创建一个 32 位(4 字节)整数。冒号后数字表示位数,值按大端序(big-endian)存储。
指定位顺序和符号
Erlang 默认使用大端序(高位在前)、无符号、整数类型。可通过修饰符覆盖这些默认行为。
- 输入
<<100:16/little>>创建小端序的 16 位整数。/little表示低位在前。 - 输入
<<-5:8/signed>>创建带符号的 8 位整数。/signed允许负值,范围变为-128到127。 - 组合多个修饰符:
<<100:32/little-signed-integer>>明确指定小端、有符号、整数类型(尽管integer是默认类型,可省略)。
常用修饰符包括:
- 端序:
big(默认)、little - 符号:
signed、unsigned(默认) - 类型:
integer(默认)、float、binary、bytes(等同于binary)
提取二进制内容
用 <<>> 语法从已有二进制中解构数据。
- 假设 有变量
Bin = <<1, 2, 3, 4>>。 - 执行
<<A, B, Rest/binary>> = Bin将前两字节赋给A和B,剩余部分作为二进制赋给Rest。结果:A=1,B=2,Rest=<<3,4>>。 - 提取固定位宽字段:
<<Flag:1, Value:15>> = <<16#4000:16>>。这里Flag取最高 1 位,Value取后续 15 位。
注意:模式匹配时,未指定类型的字段默认为 integer,未指定大小的整数默认 8 位,二进制默认匹配到末尾。
处理字符串与二进制
Erlang 字符串本质是整数列表,而二进制是原始字节序列。
- 输入
<<"hello">>创建 UTF-8 编码的二进制。每个字符转为对应字节,如<<"h">>等价于<<104>>。 - 转换字符串为二进制:使用
list_to_binary("hello")得到<<"hello">>。 - 拼接二进制:
<<Bin1/binary, Bin2/binary>>。例如<<<<"a">>/binary, <<"b">>/binary>>结果为<<"ab">>。
若需处理非 UTF-8 数据(如 Latin-1),直接使用字节值:<<195,164>> 表示 UTF-8 的 "ä",而 <<228>> 是 Latin-1 的 "ä"。
高级位级操作
<<>> 支持任意位宽,不限于 8 的倍数。
- 创建 10 位字段:
<<1023:10>>。值1023正好填满 10 位($2^{10} - 1 = 1023$)。 - 打包多个小字段:
<<Version:4, Type:4, Length:16>> = <<16#4500:32>>。这常用于解析 IP 包头:前 4 位版本号(4),接着 4 位头部长度(5),后 16 位总长度(0x00)。 - 对齐到字节边界:若总位数不是 8 的倍数,Erlang 自动在末尾补零。例如
<<1:1, 1:1>>实际生成<<192>>(二进制11000000)。
常见错误与规避
| 错误场景 | 正确做法 |
|---|---|
| 值超出位宽范围 | 计算最大值:n 位无符号整数最大为 $2^n - 1$,有符号为 $2^{n-1} - 1$ |
| 模式匹配长度不匹配 | 确保左侧总位数等于右侧二进制长度(字节对齐时注意补零) |
忘记 /binary 导致崩溃 |
提取剩余数据时务必写 Rest/binary,否则默认按 8 位整数匹配 |
实战:解析简单协议
假设协议格式:1 字节类型 + 2 字节长度 + N 字节数据。
- 接收数据
Packet = <<1, 0, 5, "hello">>。 - 执行
<<Type, Len:16, Data:Len/binary>> = Packet。 - 得到
Type=1,Len=5,Data=<<"hello">>。
此模式自动根据 Len 值决定 Data 长度,无需手动切片。
构建动态二进制
在运行时根据变量生成二进制。
- 定义变量
Size = 100,Checksum = 42。 - 构建
Header = <<Size:32, Checksum:8>>。 - 拼接完整包:
Packet = <<Header/binary, Payload/binary>>。
注意:变量在 <<>> 中直接使用,无需额外语法。
性能提示
- 避免频繁拼接:
<<A/binary, B/binary>>在循环中会产生大量中间二进制。改用 iolist(如[A, B])更高效,最后用iolist_to_binary/1转换。 - 预分配大小:若已知最终大小,一次性构建比逐步追加更快。
- 位语法编译优化:Erlang 编译器对
<<>>模式匹配高度优化,优先使用它而非binary:part/3等函数。
浮点数处理
浮点数默认以 IEEE 754 双精度(64 位)存储。
- 创建浮点二进制:
<<3.14/float>>。 - 指定精度:
<<3.14:32/float>>使用单精度(32 位)。 - 混合整数与浮点:
<<100, 3.14/float>>生成 1 字节整数 + 8 字节浮点。
注意:浮点数不能指定端序修饰符(如 /little),因其内部结构固定。
二进制推导式
类似列表推导式,但生成二进制。
- 转换列表为二进制:
<< <<X>> || X <- [1,2,3] >>结果为<<1,2,3>>。 - 处理字符串:
<< <<C/utf8>> || C <- "åäö" >>生成 UTF-8 编码二进制。 - 过滤与变换:
<< <<X*2>> || X <- [1,2,3], X > 1 >>输出<<4,6>>。
推导式中的表达式必须返回二进制片段(如 <<...>>),不能是裸整数。
调试技巧
- 打印二进制内容:使用
io:format("~w~n", [Bin])显示为<<...>>格式。 - 查看十六进制:
io:format("~16.16.0B~n", [X])打印单字节为两位十六进制。 - 检查长度:
byte_size(Bin)返回字节数,bit_size(Bin)返回总位数(可能非 8 倍数)。
文件与网络 I/O
Erlang 文件和 socket 默认以二进制模式读写。
- 读取文件:
{ok, Bin} = file:read_file("data.bin")。 - 解析内容:直接对
Bin使用<<>>模式匹配。 - 发送数据:
gen_tcp:send(Socket, <<Cmd:8, Payload/binary>>)。
始终假设外部数据是原始二进制,用 <<>> 语法安全解析,避免直接转换为字符串。
位语法速查表
以下修饰符可自由组合,顺序无关:
| 类别 | 选项 | 说明 |
|---|---|---|
| 端序 | big |
高位在前(默认) |
little |
低位在前 | |
native |
本机字节序 | |
| 符号 | signed |
有符号整数 |
unsigned |
无符号整数(默认) | |
| 类型 | integer |
整数(默认) |
float |
浮点数 | |
binary |
二进制子串 | |
bytes |
同 binary |
|
bitstring |
位串(允许非 8 倍数) |
示例:<<Val:24/little-signed-integer>> 表示小端、有符号、24 位整数。
构造 <<1, 2, 3>> 即可开始使用 Erlang 二进制。

暂无评论,快来抢沙发吧!