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

Perl:在特定字符串后拆分混合文本和二进制文件,perl,text,binaryfiles,Perl,Text,Binaryfiles,我的文件以unix分隔的文本行开始,然后切换到二进制。文本部分以特定字符串结尾,后跟换行符。之后,它是二进制的 我需要将文本部分写入一个文件,然后将二进制数据的其余部分写入另一个文件。这是我到目前为止所做的,但我仍停留在如何切换到二进制并编写剩余部分的问题上 #!/usr/bin/perl use 5.010; use strict; use warnings; my ($inputfilename, $outtextfilename, $outbinfilename) = @ARGV;

我的文件以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 "$aline\n";  # last line of the text portion
    print  "$aline\n";  # 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  "$aline\n";   # a line of the text portion
    print "$aline\n";   # a line of the text portion
    }
}

close ($in);
close ($outbin); 
#/usr/bin/perl
使用5.010;
严格使用;
使用警告;
my($inputfilename、$outtextfilename、$outbinfilename)=@ARGV;
打开(我的$in、、$outtextfilename或死亡;
我的$outbin;
打开$outbin,'>',$outbinfilename或die;
binmode$outbin;
while(my$aline=){
咀嚼$aline;
如果($aline=~/\/){#匹配表示文本部分的结尾-其余部分是二进制的
打印$outtext“$aline\n”#文本部分的最后一行
打印“$aline\n”#文本部分的最后一行
关闭($outtext);
binmode$in;#是否将输入文件更改为二进制?
#我该怎么做才能将文件中的所有剩余字节作为二进制文件复制到$outbin??
死亡
}否则{
打印$outtext“$aline\n”#文本部分的一行
打印“$aline\n”#文本部分的一行
}
}
收盘价(美元);
关闭($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 File\n";
while (my $aline = <$in>) {
  chomp $aline;
  if($aline =~ /\<\/FileSystem\>/) {   # a match indicates the end of the text portion - the rest is binary
    print $outtext "$aline\n";  # last line of the text portion
    print  "$aline\n";  # 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 "\nDone\n";
    close $outbin;
    last;

    } else {
    print $outtext  "$aline\n";   # a line of the text portion
    print "$aline\n";   # a line of the text portion
    }
}
!/usr/bin/perl
使用5.010;
严格使用;
使用警告;
my($inputfilename、$outtextfilename、$outbinfilename)=@ARGV;
打开(我的$in、、$outtextfilename或死亡;
我的$outbin;
打开$outbin,'>',$outbinfilename或die;
binmode$outbin;
打印“起始文件\n”;
while(my$aline=){
咀嚼$aline;
如果($aline=~/\/){#匹配表示文本部分的结尾-其余部分是二进制的
打印$outtext“$aline\n”#文本部分的最后一行
打印“$aline\n”#文本部分的最后一行
关闭($outtext);
binmode$in;#将输入文件更改为二进制
我的$cont='';
打印“处理二进制部分”;
而(1){
我的$success=读取$in,$cont,1000000,长度($cont);
die$!如果未定义$success;
最后,如果不是$success;
“打印”;
}
收盘价(美元);
打印$outbin$cont;
打印“\n完成\n”;
关闭$outbin;
最后;
}否则{
打印$outtext“$aline\n”#文本部分的一行
打印“$aline\n”#文本部分的一行
}
}

最简单的方法可能是对所有内容使用二进制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;
}
!/usr/bin/perl
严格使用;
使用警告;
my($inputfilename、$outtextfilename、$outbinfilename)=@ARGV;
打开我的$in_fh,':raw',$outbinfilename
或者死“$0:无法打开$outbinfilename进行写入:$!\n”;
#处理文本部分
while(my$line=readline$in_fh){
打印$out\u txt\u fh$行;
最后一个if$line=~m{};
}
#处理二进制部件
while(读取$in_fh,我的$buffer,4096){
打印$out\u bin\u fh$缓冲区;
}
这个版本的代码逐行处理文本部分,并以4096字节的块处理二进制部分(不考虑内部缓冲)

或者,如果标记文本部分结尾的字符序列正好是
“\n”
,我们可能会有点冒失:

# process text part
{
    local $/ = "</FileSystem>\n";
    if (my $line = readline $in_fh) {
        print $out_txt_fh $line;
    }
}
#处理文本部分
{
本地$/=“\n”;
如果(我的$line=读线$in_fh){
打印$out\u txt\u fh$行;
}
}

我们临时将行尾标记从
“\n”
切换到
“\n”
,并读取单个“行”,它包含所有的文本部分。这假设文本部分足够小,可以轻松地放入内存。脚本的其余部分是相同的。

您必须从1999年开始编写与perl兼容的代码吗?如果不需要,请
使用strict;使用warnings;
,使用3参数open,并使用普通变量,而不是裸字文件句柄。不需要esn不必与1999兼容。我显然不是Perl专家。我从现有脚本(可能有那么旧)中获取了一些代码,并试图表达这个问题。我将用更好的编译代码编辑上面的代码块,但仍然缺少二进制输出函数。文件有多大?[KB,MB,GB]谢谢@melpomene,这很有效。我能够适应它,再加上从中提出解决方案。我无法在此评论中发布代码,因此我将尝试添加另一个回复来说明我是如何做到的。我也无法添加回复(除了“回答你的问题”,所以我将使用最终的工作代码编辑原始帖子。