Perl:在特定字符串之后拆分混合文本和二进制文件



我的文件以 unix 分隔的文本行开头,然后切换到二进制。文本部分以特定字符串结尾,后跟换行符。之后它是二进制的。

我需要将文本部分写入一个文件,然后将其余的二进制数据写入另一个文件。 这是我到目前为止所拥有的,但我坚持如何切换到二进制并编写其余部分。

#!/usr/bin/perl
use 5.010;
use strict; 
use warnings;

my ($inputfilename, $outtextfilename, $outbinfilename) = @ARGV;
open(my $in, '<:encoding(UTF-8)', $inputfilename)
or die "Could not open file '$inputfilename' $!";
open my $outtext, '>', $outtextfilename or die;
my $outbin;
open $outbin, '>', $outbinfilename or die;
binmode $outbin;

while (my $aline = <$in>) {
chomp $aline;
if($aline =~ /</FileSystem>/) {   # a match indicates the end of the text portion - the rest is binary
print $outtext "$alinen";  # last line of the text portion
print  "$alinen";  # last line of the text portion
close ($outtext); 
binmode $in;  # change input file to binary? 
# what do I do here to copy all remaining bytes in file as binary to $outbin??
die;
} else {
print $outtext  "$alinen";   # a line of the text portion
print "$alinen";   # a line of the text portion
}
}
close ($in);
close ($outbin); 

编辑 - 最终代码:

#!/usr/bin/perl
use 5.010;
use strict; 
use warnings;

my ($inputfilename, $outtextfilename, $outbinfilename) = @ARGV;
open(my $in, '<', $inputfilename)
or die "Could not open file '$inputfilename' $!";
open my $outtext, '>', $outtextfilename or die;
my $outbin;
open $outbin, '>', $outbinfilename or die;
binmode $outbin;

print "Starting Filen";
while (my $aline = <$in>) {
chomp $aline;
if($aline =~ /</FileSystem>/) {   # a match indicates the end of the text portion - the rest is binary
print $outtext "$alinen";  # last line of the text portion
print  "$alinen";  # last line of the text portion
close ($outtext); 
binmode $in;  # change input file to binary
my $cont = '';
print "processing binary portion";
while (1) {
my $success = read $in, $cont, 1000000, length($cont);
die $! if not defined $success;
last if not $success;
print ".";
}
close ($in);
print $outbin $cont;
print "nDonen";
close $outbin;
last;
} else {
print $outtext  "$alinen";   # a line of the text portion
print "$alinen";   # a line of the text portion
}
}

最简单的方法可能是对所有内容使用二进制 I/O。这样我们就不必担心中途切换文件模式,并且在 unix 上,文本模式和二进制模式之间没有任何区别(除了在编码方面,但在这里我们只想复制字节不变)。

根据文件的纯文本部分的大小,我们可以逐行处理它,也可以一次将其全部读入内存。

#!/usr/bin/perl
use strict; 
use warnings;
my ($inputfilename, $outtextfilename, $outbinfilename) = @ARGV;
open my $in_fh, '<:raw', $inputfilename
or die "$0: can't open $inputfilename for reading: $!n";
open my $out_txt_fh, '>:raw', $outtextfilename
or die "$0: can't open $outtextfilename for writing: $!n";
open my $out_bin_fh, '>:raw', $outbinfilename
or die "$0: can't open $outbinfilename for writing: $!n";
# process text part
while (my $line = readline $in_fh) {
print $out_txt_fh $line;
last if $line =~ m{</FileSystem>};
}
# process binary part
while (read $in_fh, my $buffer, 4096) {
print $out_bin_fh $buffer;
}

此版本的代码逐行处理文本部分,并以 4096 字节的块处理二进制部分(不考虑内部缓冲)。

或者,如果标记文本部分末尾的字符序列正好"</FileSystem>n",我们可以有点厚脸皮:

# process text part
{
local $/ = "</FileSystem>n";
if (my $line = readline $in_fh) {
print $out_txt_fh $line;
}
}

我们暂时将行尾标记从"n"切换到"</FileSystem>n",并读取包含所有文本部分的单个"行"。这假设文本部分足够小,可以舒适地放入内存中。脚本的其余部分是相同的。

最新更新