我有一个二进制文件。我想从$marker + $step
到$marker
(或文件末尾)提取所有数据。
数据示例:
23 40 92 34 32 09 84 39 02 89 30 fe 90 38 01 02 03 f1 f2
00 00 00 22 33 44 56 77 22 aa bb cc dd ef ff 11 11 ff dd cc cc cc 22 80 ee {{1 00 00 00 22 33 44 56 23 40 92 34 32 dd cc cc 22 33 44 22 33 44 01 02 03 f1 f2
00 00 00 22 33 44 56 77 22 FF FF FF 52 FF FF 52 00 00 00 00 00 00 00
它包含三个块,我需要什么
1)
01 02 03 f1 f2
2)
00 00 00 22 33 44 56 77 22 aa bb cc dd ee ff 00 11 ff dd cc cc cc 22 80 ee
3)
00 00 00 22 33 44 56 23 40 92 34 32 dd cc cc 22 33 44 22 33 44
我从未使用过perl的二进制文件。
00 00 00 22 33 44 56 77 22 FF FF FF 52 FF FF 52 00 00 00 00 00 00 00
因此,我必须获得3个.dat文件。
请帮助我实现这个伪代码。请写一个简单的例子。
答案 0 :(得分:5)
Perl正则表达式对二进制数据和可读文本一样满意,并且可以使用raw
模式打开二进制文件,以避免转换行结尾。
这是一个解决方案,可将整个文件读入内存并扫描其中的标记字符串。
use strict;
use warnings;
my $filename = shift;
my $binary = do {
open my $fh, '<:raw', $filename or die $!;
local $/;
<$fh>;
};
my $marker = "\x01\x02\x03\xf1\xf2";
while ( $binary =~ /$marker(.*?)(?=$marker|\z)/sg ) {
my @hex = map { sprintf '%02X', $_ } unpack 'C*', $1;
print "@hex\n";
}
<强>输出强>
00 00 00 22 33 44 56 77 22 AA BB CC DD EE FF 00 11 FF DD CC CC CC 22 80 EE
00 00 00 22 33 44 56 23 40 92 34 32 DD CC CC 22 33 44 22 33 44
00 00 00 22 33 44 56 77 22 FF FF FF 52 FF FF 52 00 00 00 00 00 00 00
<强>更新强>
如果文件很大,或者您只是想要这个想法,可以将输入记录分隔符设置为标记字符串。然后对文件执行readline
操作将获取并包括文件中下一次出现的标记模式。这意味着每条记录都会随着 next 记录开头的标记一起被读取,但是无论如何它都会被删除无关紧要。
use strict;
use warnings;
my $filename = shift;
my $marker = "\x01\x02\x03\xf1\xf2";
open my $fh, '<:raw', $filename or die $!;
local $/ = $marker;
<$fh>; # Drop the data up to and including the first marker
while (<$fh>) {
chomp; # Remove the marker string from the end, if any
my @hex = map { sprintf '%02X', $_ } unpack 'C*';
print "@hex\n";
}
输出与上述程序的输出相同。
<强>更新强>
道歉。我刚刚阅读了该程序所需的输出。该程序使用上面的第二种技术,但写入一系列EXTFILE.dat
文件而不是转储十六进制数据。请注意,再次需要raw
的开放模式。
use strict;
use warnings;
my $filename = shift // 'file.bin';
my $marker = "\x01\x02\x03\xf1\xf2";
open my $fh, '<:raw', $filename or die $!;
local $/ = $marker;
<$fh>; # Drop the data up to and including the first marker
my $count;
while (my $record = <$fh>) {
chomp $record;
my $outfile = sprintf 'EXTFILE_%d.dat', ++$count;
open my $out_fh, '>:raw', $outfile or die $!;
print $out_fh $record;
close $out_fh or die $!;
}