Perl unpack 函数
最后修改于 2025 年 4 月 4 日
Perl 的 unpack
函数将二进制数据转换为 Perl 值。它是 pack
的逆操作,对于二进制数据处理至关重要。
unpack
使用模板字符串来指定如何解释二进制数据。它可以从二进制结构中提取数字、字符串和其他数据类型。
基本定义
- 模板:指定数据格式的字符串(例如,“N”表示 32 位无符号整数)
- 二进制数据:需要解释的原始字节
- 字节序:端序(大端 vs 小端)
- 对齐:数据结构填充要求
- 字段:二进制结构中的单个数据元素
unpack 的基本用法
unpack
最简单的用法是从二进制数据中提取单个值。
#!/usr/bin/perl use strict; use warnings; use v5.34.0; my $binary = pack("N", 0xDEADBEEF); my ($number) = unpack("N", $binary); printf "Binary: %v02X\n", $binary; printf "Unpacked: 0x%08X\n", $number;
我们打包一个 32 位无符号整数,然后将其解包。 “N”模板指定了网络(大端)字节序。结果与我们的原始值匹配。
$ ./basic.pl Binary: DE.AD.BE.EF Unpacked: 0xDEADBEEF
提取多个值
unpack
可以使用单个模板提取多个值。
#!/usr/bin/perl use strict; use warnings; use v5.34.0; my $data = pack("NnA4", 0xCAFEBABE, 42, "Perl"); my ($num1, $num2, $str) = unpack("NnA4", $data); printf "Numbers: 0x%08X, %d\n", $num1, $num2; print "String: $str\n";
此示例打包和解包三个值:一个 32 位整数、一个 16 位整数和一个 4 字节字符串。模板“NnA4”匹配打包的数据结构。
$ ./multiple.pl Numbers: 0xCAFEBABE, 42 String: Perl
字节序转换
unpack
可以在不同的字节序之间进行转换。
#!/usr/bin/perl use strict; use warnings; use v5.34.0; my $little_endian = pack("V", 0x12345678); my ($big_endian) = unpack("N", $little_endian); printf "Little-endian: %v02X\n", $little_endian; printf "Converted to big-endian: 0x%08X\n", $big_endian;
我们将一个值以小端格式(“V”)打包,并以大端格式(“N”)解包。这演示了不同架构之间的字节序转换。
$ ./endian.pl Little-endian: 78.56.34.12 Converted to big-endian: 0x78563412
字符串提取
unpack
可以提取具有特定长度和编码的字符串。
#!/usr/bin/perl use strict; use warnings; use v5.34.0; my $binary = pack("A10A5", "Hello", "World"); my ($str1, $str2) = unpack("A10A5", $binary); print "First string: '$str1'\n"; print "Second string: '$str2'\n";
此示例打包和解包两个空格填充的字符串。“A”模板提取 ASCII 字符串,默认情况下会修剪尾部空格。
$ ./strings.pl First string: 'Hello' Second string: 'World'
位操作
unpack
可以从二进制数据中提取单个位和位字段。
#!/usr/bin/perl use strict; use warnings; use v5.34.0; my $flags = pack("C", 0b10101100); my ($bitfield) = unpack("b8", $flags); print "Binary representation: $bitfield\n"; print "Bits 7-6: ", substr($bitfield, 0, 2), "\n"; print "Bit 3: ", substr($bitfield, 5, 1), "\n";
我们打包一个具有特定位模式的字节,并将其解包为二进制字符串。“b”模板使我们能够访问单个位进行检查。
$ ./bits.pl Binary representation: 00110101 Bits 7-6: 00 Bit 3: 1
十六进制转储解析
unpack
可以解析二进制数据的十六进制字符串表示。
#!/usr/bin/perl use strict; use warnings; use v5.34.0; my $hex_string = "DEADBEEFCAFE"; my $binary = pack("H*", $hex_string); my @bytes = unpack("C*", $binary); print "Hex string: $hex_string\n"; print "Bytes: ", join(", ", map { sprintf "0x%02X", $_ } @bytes), "\n";
这会将十六进制字符串转换为二进制,然后将其解包为单个字节。“H”模板处理十六进制数据,而“C”提取无符号字节。
$ ./hexdump.pl Hex string: DEADBEEFCAFE Bytes: 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE
复杂结构解析
unpack
可以处理具有混合数据类型的复杂二进制结构。
#!/usr/bin/perl use strict; use warnings; use v5.34.0; # Simulate a network packet header my $packet = pack("nnNNa8", 0x8000, # version and flags 42, # packet ID time(), # timestamp 128, # data length "payload" # data type ); my ($version_flags, $id, $timestamp, $length, $type) = unpack("nnNNa8", $packet); printf "Version: %d\n", ($version_flags >> 12) & 0xF; printf "Packet ID: %d\n", $id; printf "Timestamp: %s\n", scalar localtime $timestamp; printf "Data length: %d\n", $length; printf "Data type: '%s'\n", $type;
此示例演示了解析类似于网络数据包头的复杂二进制结构。我们使用不同的数据类型和大小提取和解释多个字段。
$ ./complex.pl Version: 8 Packet ID: 42 Timestamp: Wed Apr 5 14:30:22 2025 Data length: 128 Data type: 'payload'
最佳实践
- 验证输入:在解包前检查二进制数据长度
- 使用描述性模板:使格式可读且易于维护
- 处理字节序:明确指定字节序要求
- 检查返回值:验证解包后的数据是否符合预期
- 文档格式:详细注释复杂的二进制结构
来源
本教程介绍了 Perl 的 unpack
函数,并通过实际示例演示了各种场景下的二进制数据处理。
作者
列出 所有 Perl 教程。