如何在Perl中创建二进制文件?

37
举例来说,我想创建一个名为sample.bin的文件,并输入一个数字,比如255,以便将255以小端格式保存在文件中,即FF 00。或者将3826转换为F2 0E。
我按照perldoc中所说的方法使用了binmode。

我认为最重要的提示是在print的perldoc中的这句话:打印一个字符串或一组字符串。 ...而不是数字。我也曾经掉入过这个陷阱。 - MattTT
3个回答

44

Perl的pack函数将根据模板返回“二进制”数据。

open(my $out, '>:raw', 'sample.bin') or die "Unable to open: $!";
print $out pack('s<', 255);
close($out);

在上面的示例中,'s' 表示输出一个 short(16位),'<' 强制将其设置为小端模式。

此外,:raw 参数告诉 open 在需要时将文件句柄放入二进制模式(等同于使用 binmode)。有关以不同格式进行输入/输出的更多信息可以参考PerlIO 手册页。


哇,我明白了,谢谢。我是PERL的新手,所以我想我会去perldoc查看pack函数。谢谢。 - domlao
pack是一个不错的函数。特别要注意哪些模板字符用于编码小端和大端值。 - mob
3
请记住,这里使用的编程语言是 Perl,解释器/编译器也是 Perl。我并不是要挑剔,但是错误地大小写编写 Perl 这个词是一个常见的问题。 - Drew Stephens
4
@Adam,请不要使用open函数的两个参数形式。当与来自变量的文件名配对时,它会创建一个巨大的安全漏洞,等待被利用。使用词汇文件句柄也是一个好主意(它限制了文件句柄的范围)。你的open语句应该重写为open( my $out, '>', 'sample.bin') or die "Blah $!"; - daotoad

10
你可以使用pack来生成二进制数据。对于复杂结构,Convert::Binary::C特别方便。
CBC解析C头文件(可以从目录或脚本变量中获取)。它使用头文件中的信息来packunpack二进制数据。
当然,如果你想使用这个模块,最好懂一些C。
CBC让你能够指定C类型的字节序和大小,甚至可以指定函数来转换本地Perl类型和二进制文件中的数据。我用这个功能来处理编码和解码定点数。
对于非常基本的例子,您可以使用以下代码:
use strict;
use warnings;

use IO::File; 

use Convert::Binary::C;

my $c = Convert::Binary::C->new('ByteOrder' => 'LittleEndian');

my $packed = $c->pack( 'short int', 0xFF );

print $packed;

my $fh = IO::File->new( 'outfile', '>' ) 
  or die "Unable to open outfile - $!\n";

$fh->binmode;

$fh->print( $packed );

在这个例子中,CBC并没有真正发挥其作用,因为它只使用了一个短整型。如果您需要处理可能从几个不同的C头文件中提取typedef的复杂结构体,那么有了这个工具,您将感到非常高兴。

由于您是Perl的新手,我建议您始终使用use strictuse warnings。此外,您可以使用use diagnostics来获取更详细的错误消息解释。无论是本网站还是Perlmonks都有很多适合初学者的好信息和许多非常聪明、熟练的人愿意帮助您。

顺便说一句,如果您决定使用pack,请查看pack教程,它有助于澄清有些令人费解的pack文档。


6

是的,使用binmode

为了您的娱乐(如果不是教育),我第一次尝试创建二进制文件时包括了binmode STDOUT和以下内容:

sub output_word {
    $word = $_[0];
    $lsb  = $word % 256;
    $msb  = int($word/256);
    print OUT chr($lsb) . chr($msb);
    return $word;
} 

求你了,别用这段代码!它来自于我不懂更好的写法的时候。

虽然可以说我现在还是不太懂,但我把它重现在这里是为了展示即使使用愚蠢的方法,你也能够控制字节的顺序,并且因为我需要坦白。

一个更好的方法是使用像Adam Batkin建议的pack

我想我在 Perl 4 中犯了上述暴行。那是很久以前的事了。我真希望我能忘掉它...


我一定会使用这种技术。除了效率之外,我没有看到任何问题。我更感兴趣的是用易懂的代码快速解决我的问题,而不是学习正确的Perl方法。谢谢您的发布。 - NXT
老实说,我也不认为这有什么问题。Pack 可能更有效率,但这是完全可以的代码。我经常在 C 中使用类似这样的例程来处理在未知字节序平台上的已知字节序数据。除了掩码和移位而不是除法,因为 C 具有更强的类型。但概念相同。 - SirNickity

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接