2009-07-16 67 views
3

感谢大家提前。如何访问在Perl二进制标量的第n个字节?

我想访问一个二进制标量的第n个字节。例如,你可以得到所有的文件数据在一个标量变量...

试想一下,二进制数据被收集到标...

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

$ thisByteData是原始二进制数据。当我使用的长度($ thisByteData)我得到的字节数回,这样的Perl不知道它有多大。我的问题是如何访问第N个字节?

边注:我的功能是要获得这个二进制标量,它在我的功能,我要访问的第N个字节。有关如何收集这些数据的帮助表示赞赏,但不是我所期待的。无论怎样其他程序员要收集二进制数据是由他们决定,我的工作是它传递时,为了获得第N个字节我:)

再次感谢这么多的帮助大家!


感谢@muteW让我获得了前所未有的进步。我想我不理解正确解压(...)。

print(unpack("N1", $thisByteData)); 
print(unpack("x N1", $thisByteData)); 
print(unpack("x0 N1", $thisByteData)); 

还是返回了以下内容:

4292411360 
3640647680 
4292411360 

我会承担这些三线都会访问相同的(第一个)字节。不使用“x”只是“x”和“x $ pos”会产生意想不到的结果。

我也试过这个...

print(unpack("x0 N1", $thisByteData)); 
print(unpack("x1 N1", $thisByteData)); 
print(unpack("x2 N1", $thisByteData)); 

它返回......同样的事情,最后的测试......

4292411360 
3640647680 
4292411360 

我definatly失去了一些东西有关如何解包工作。


如果我这样做...

print(oct("0x". unpack("x0 H2", $thisByteData))); 
print(oct("0x". unpack("x1 H2", $thisByteData))); 
print(oct("0x". unpack("x2 H2", $thisByteData))); 

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

255 
216 
255 

无法解压缩这个给我自己,而不必使用OCT()?


作为一个方面说明:我觉得用“X $ POS N1”的时候,我发现了2的这些字节整数的补充。我期待这些作为前3个字节。

255 
216 
255 

再次感谢所有人的帮助。


特别感谢@布赖恩d FOY和@muteW ......现在我知道如何访问我的二进制使用标解压缩(...)的第N个字节。我现在有一个新问题需要解决,与这个问题无关。再次感谢所有帮助家伙!

这给了我希望的结果......

print(unpack("x0 C1", $thisByteData)); 
print(unpack("x1 C1", $thisByteData)); 
print(unpack("x2 C1", $thisByteData)); 

解包(......)有一吨的选项,因此我建议任何人谁读这读包/解压文件,以获得字节数据结果的选择。我也没有尝试使用@brian提到的Tie选项,我想尽可能简化代码。

+0

请编辑该评论到您原来的问题。 – 2009-07-16 21:30:17

+1

处理二进制数据时,应该在打开文件句柄(即开始读/写之前)后立即在文件句柄上使用`binmode`。 – 2009-07-16 23:17:21

+0

你想做什么?如果你想从图像文件中提取信息,那么可能已经有一个模块可以为你做。 – 2009-07-16 23:40:31

回答

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 

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

编辑 - 您的评论如下显示,您错过了第一个字节的高位nybble('f')。我不确定为什么会发生这种情况,但这里有一种可行的替代方法,同时我会进一步研究解包的行为。

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 

使用该输出为前四个字节是 - 0xff的0xd8 0xff的0xe0的哪些相匹配的documentation

2

Perl内置变量$/(或$INPUT_RECORD_SEPARATOR如果你是use ing English)控制Perl的“行”的想法。默认情况下,它设置为"\n",所以行由换行符(duh)分隔,但您可以将其更改为任何其他字符串。或者将其更改为对某个数字的引用:

$/ = \1; 
while(<FILE>) { 
    # read file 
} 

将其设置为对数字的引用将告诉Perl“行”是该字节数。

现在,你究竟想要做什么?可能有很多模块可以做你想做的事情,也可能更有效率。如果你只是想学会如何去做,那就去吧,但是如果你有一个特定的任务,不要重新发明轮子(除非你想)。

编辑:由于在评论jrockway ...

如果你有Unicode数据,这可能不是读一个字节,但是一个字符,但如果出现这种情况,你应该能够use bytes;关闭自动字节到字符转换。

现在,你说你想一次读取所有数据,然后将它传递给一个函数。让我们做到这一点:

my $data; 
{ 
    local $/; 
    $data = <FILE>; 
} 

或者这样:

my $data = join("", <FILE>); 

或者有些人会建议File::Slurp模块,但我认为这是一个有点矫枉过正。然而,让我们整个文件转换成字节数组:

use bytes; 

... 

my @data = split(//, join("", <FILE>)); 

然后我们有一个字节数组,我们可以传递给一个函数。喜欢?

1

不知道更多关于你想与您的数据做什么,这样的事情会遍历字节的文件中:

open(SOURCE, "wl.jpg"); 
my $byte; 
while(read SOURCE, $byte, 1) { 
    # Do something with the contents of $byte 
} 
close SOURCE; 

小心在你的例子中使用的concatanation;你可能会以换行符结束,这绝对不是你在阅读二进制文件时想要发生的事情。 (这也是低效率的不断扩大标而读它。)这是拖带整个文件到Perl标量的惯用方式:

open(SOURCE, "<", "wl.jpg"); 
local $/ = undef; 
my $big_binary_data = <SOURCE>; 
close SOURCE; 
3

我认为正确的答案涉及包/解压缩,但是这也可能工作:

use bytes; 
while($bytestring =~ /(.)/g){ 
    my $byte = $1; 
    ... 
} 

“用字节”确保你永远看不到的人物 - 但是,如果你有一个字符串,并处理它作为一个字节,你正在做的事情是错误的。Perl的内部字符编码是未定义的,所以在“使用字节”下的字符串中看到的数据几乎没有意义。

8

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

但是,你可以直接从文件中读取它,而没有所有这些字符串废话人们一直在填补你的头。 :)使用sysopen和正确的选项打开文件,使用seek将自己放在您想要的位置,然后使用sysread阅读所需内容。

您可以跳过openreadline正在为您做的事情的所有解决方法。如果你只是要关闭他们的所有功能,甚至不要使用它们。

相关问题