如何在Perl中访问二进制标量的第n个字节?

rak*_*van 5 perl loops bytearray

感谢大家提前.

我想访问二进制标量的第n个字节.例如,您可以在一个标量变量中获取所有文件数据...

想象一下,二进制数据被收集到标量中......

open(SOURCE, "<", "wl.jpg"); 
my $thisByteData = undef; 
while(<SOURCE>){$thisByteData .= $_;} 
close SOURCE; 
Run Code Online (Sandbox Code Playgroud)

$ thisByteData是原始二进制数据.当我使用length($ thisByteData)时,我得到了字节数,所以Perl知道它有多大.我的问题是如何访问第N个字节?

旁注:我的函数将接收这个二进制标量,它在我的函数中,我想访问第N个字节.关于如何收集这些数据的帮助是值得赞赏的,但不是我正在寻找的.无论其他程序员想要收集二进制数据的方式取决于他们,我的工作是在传递给我时获取第N个字节:)

再次感谢所有人的帮助!


感谢@muteW让我比以往任何时候都更进一步.我想我不理解unpack(...)正确.

print(unpack("N1", $thisByteData));
print(unpack("x N1", $thisByteData));
print(unpack("x0 N1", $thisByteData));
Run Code Online (Sandbox Code Playgroud)

返回以下内容:

4292411360
3640647680
4292411360
Run Code Online (Sandbox Code Playgroud)

我假设这3行都会访问相同的(第一个)字节.不使用"x"只是"x"和"x $ pos"会产生意想不到的结果.

我也尝试过这个......

print(unpack("x0 N1", $thisByteData));
print(unpack("x1 N1", $thisByteData));
print(unpack("x2 N1", $thisByteData));
Run Code Online (Sandbox Code Playgroud)

返回...与上次测试相同...

4292411360
3640647680
4292411360
Run Code Online (Sandbox Code Playgroud)

我肯定错过了一些关于unpack如何工作的东西.


如果我这样做......

print(oct("0x". unpack("x0 H2", $thisByteData)));
print(oct("0x". unpack("x1 H2", $thisByteData)));
print(oct("0x". unpack("x2 H2", $thisByteData)));
Run Code Online (Sandbox Code Playgroud)

我得到了我所期待的......

255
216
255
Run Code Online (Sandbox Code Playgroud)

无需使用oct()就无法解压缩给我自己?


作为旁注:我认为在使用"x $ pos N1"时,我得到了这些字节整数的2的补码.我期待这些作为前3个字节.

255
216
255
Run Code Online (Sandbox Code Playgroud)

再次感谢所有人的帮助.


特别感谢@brian d foy和@muteW ...我现在知道如何使用unpack(...)访问我的二进制标量的第N个字节.我现在有一个新问题要解决,这与这个问题无关.再次感谢所有帮助人员!

这给了我想要的结果......

print(unpack("x0 C1", $thisByteData));
print(unpack("x1 C1", $thisByteData));
print(unpack("x2 C1", $thisByteData));
Run Code Online (Sandbox Code Playgroud)

unpack(...)有很多选项,所以我建议其他读取这个选项的人阅读pack/unpack文档以获得他们选择的字节数据结果.我也没有尝试使用@brian提到的Tie选项,我希望尽可能简化代码.

bri*_*foy 8

如果你有一个字符串中的数据,并且你想要获得某个字节,请使用substr,只要你将字符串视为字节开头即可.

但是,您可以直接从文件中读取它,而不是所有这些字符串无意义的人都在填补你的头脑.:)使用sysopen和正确的选项打开文件,使用seek将自己放在想要的位置,并阅读sysread所需的内容.

你跳过所有的东西,变通办法open,并readline试图为你做.如果您要关闭所有功能,请不要使用它们.


aks*_*aks 3

由于 $thisByteData 中已有文件内容,因此您可以使用pack / unpack来访问第 n 个字节。

sub getNthByte {
  my ($pos) = @_;
  return unpack("x$pos b1", $thisByteData);
}

#x$pos - treats $pos bytes as null bytes(effectively skipping over them) 
#b1    - returns the next byte as a bit string
Run Code Online (Sandbox Code Playgroud)

通读包文档,了解可在模板中使用的参数来获取不同的返回值。

编辑 - 下面的评论表明您缺少第一个字节的高位 nybble ('f')。我不确定为什么会发生这种情况,但这是一种可行的替代方法,同时我将进一步研究 unpack 的行为。

sub getNthByte {
  my ($pos) = @_;
  return unpack("x[$pos]H2", $binData);
}

(my $hex = unpack("H*", $binData)) =~ s/(..)/$1 /g;
#To convert the entire data in one go
Run Code Online (Sandbox Code Playgroud)

使用此命令,前四个字节的输出为 - 0xff 0xd8 0xff 0xe0,与文档相符。