ZetCode

Perl unpack 函数

最后修改于 2025 年 4 月 4 日

Perl 的 unpack 函数将二进制数据转换为 Perl 值。它是 pack 的逆操作,对于二进制数据处理至关重要。

unpack 使用模板字符串来指定如何解释二进制数据。它可以从二进制结构中提取数字、字符串和其他数据类型。

基本定义

unpack 的基本用法

unpack 最简单的用法是从二进制数据中提取单个值。

basic.pl
#!/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 可以使用单个模板提取多个值。

multiple.pl
#!/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 可以在不同的字节序之间进行转换。

endian.pl
#!/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 可以提取具有特定长度和编码的字符串。

strings.pl
#!/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 可以从二进制数据中提取单个位和位字段。

bits.pl
#!/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 可以解析二进制数据的十六进制字符串表示。

hexdump.pl
#!/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 可以处理具有混合数据类型的复杂二进制结构。

complex.pl
#!/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 的 unpack 函数,并通过实际示例演示了各种场景下的二进制数据处理。

作者

我的名字是 Jan Bodnar,我是一名热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。至今,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 Perl 教程