0

我正在读取一个二进制文件格式,它以 4 个常量校验字节开始,然后是 3 个八位字节,指示记录的数据部分的长度。我可以如下解码:

read($fh, $x, 7) or do {
  last if eof;
  die "Can't read: $!";
};
my ($type, $l1, $l2, $l3) = unpack("a4 C3", $x);
my $length = $l1 << 16 | $l2 << 8 | $l3;

有没有更直接的方法来读取那个 3 字节的值,而不需要中间变量?我pack可能在规格中遗漏了什么?除了十六进制编码和其他业余爱好者之外,我没有使用pack太多。

4

4 回答 4

2

您可以在字符串中插入一个空字节,以便能够使用“N”格式:

substr($x, 4, 0, "\0");
my ($type, $length) = unpack "a4 N", $x;

编辑:或者分两步解压:

my ($type, $length) = unpack "a4 a3", $x;
$length = unpack "N", "\0" . $length;
于 2013-03-19T23:27:30.883 回答
2
my $type = unpack("a4", $x);
my $len  = unpack("N", "\0".substr($x, 4));

或者

my ($type, $plen) = unpack("a4 a3", $x);
my $len = unpack("N", "\0$plen");
于 2013-03-20T01:11:53.537 回答
1

不,unpack不支持 3 字节(或任意长度)整数,但您可以使用无符号 16 位 big-endian int 来节省一些工作:

my ($type, $l1, $l23) = unpack("a4 Cn", $x);
my $length = $l1 << 16 | $l23;
于 2013-03-19T23:24:37.470 回答
1

解决方案:您获取类型的方法很好。但是,我建议您将长度单独解压缩为一个四字节整数,然后丢弃这四个字节中的第一个字节。即使它重叠并丢弃类型的最后一个字节,这也会更有效。

my $type = unpack("a4", $x);
my $length = unpack("x3N", $x); # skips the first 3 bytes of your original 7-byte string
$length = $length & 0xFFFFFF; # returns only the last 3 bytes of the four-byte integer
于 2013-03-20T00:35:23.130 回答