3

我有两个相关的问题(在 Perl 中):

  1. 将数据写入二进制文件,格式为:单个位标志后跟 8 位
  2. 回读相同的格式

我尝试了这个(以及其他变体,但对于我的生活,我无法弄清楚):

binmode(OUT);
my $bit = pack("B1", '1');
my $byte = pack("H2", "02");
print OUT $bit . $byte;

使用十六进制编辑器,我看到我得到 16 位:

1000000000000020

我想要的是 9 位:

100000020

另外:假设我写出其中两个模式。这意味着我最终得到 9 + 9 = 18 位。我不确定如何处理最后一个字节(填充?)

这是为了压缩和解压缩文件,空间非常宝贵。我希望有一些我不知道的简单的惯用方式来做到这一点。

4

2 回答 2

5

文件是字节序列。如果要打印位,则必须使用某种形式的缓冲。

my $bits = '';
$bits .= '1';                                        # Add 1 bit.
$bits .= unpack('B8', pack('C', 0x02));              # Add 8 bits.
$bits .= substr(unpack('B8', pack('C', 0x02)), -6);  # Add 6 bits.

这会打印尽可能多的缓冲区:

my $len = ( length($bits) >> 3 ) << 3;
print($fh, pack('B*', substr($bits, 0, $len, '')));

您最终需要填充缓冲区,以便您拥有 8 位的倍数,以便清除其余部分。你可以简单地用零填充。

$bits .= "0" x ( -length($bits) % 8 );

但是,如果您很聪明,您可以提出一个填充方案,用于指示文件实际结束的位置。请记住,您不能再仅依赖文件长度。如果您不使用智能填充方案,则必须使用另一种方法。

智能填充方案的一个示例是:

$bits .= "0";
$bits .= "1" x ( -length($bits) % 8 );

然后,要取消填充,请删除所有尾随1位和0之前的位。

于 2013-01-12T05:46:44.033 回答
2

您可以使用 Bit::Vector 更轻松地管理您的位和转换,

use Bit::Vector;

my $bit = Bit::Vector->new_Bin( 1, '1' );

my $byte     = Bit::Vector->new_Bin( 8, '00000010' );
my $byte_9   = Bit::Vector->new_Bin( 9, '000000010' );
my $nineBits = Bit::Vector->new_Bin( 9, '100000000' );
my $carry    = Bit::Vector->new_Bin( 9, '000000000' );
my $ORed     = Bit::Vector->new_Bin( 9, '000000000' );
my $added    = Bit::Vector->new_Bin( 9, '000000000' );


$ORed->Union($nineBits,$byte_9);

print "bit: 0x". $bit->to_Hex(). "\n";
print "byte 2: 0x". $byte->to_Hex(). "\n";
print "nineBits: 0x". $nineBits->to_Hex(). "\n";
print "nineBits: 0x". $nineBits->to_Bin(). "\n";
print "ORed bit and byte 0x". $ORed->to_Dec(). "\n";

open BINOUT, ">out.bin"
    or die "\nCan't open out.bin for writing: $!\n";

binmode BINOUT;

print BINOUT pack ('B*', $ORed->to_Bin()) ."\n"

这是输出

>perl bitstuff.pl
bit: 0x1
byte 2: 0x02
nineBits: 0x100
nineBits: 0x100000000
ORed bit and byte 0x-254
>cat out.bin 
\201^@
于 2013-01-12T05:46:54.400 回答