我的文件以 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"
,并读取包含所有文本部分的单个"行"。这假设文本部分足够小,可以舒适地放入内存中。脚本的其余部分是相同的。