Perl: разделить смешанный текст и двоичный файл после определенной строки - PullRequest
1 голос
/ 01 июня 2019

У меня есть файлы, которые начинаются с текстовых строк, разделенных 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
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
    }
}

1 Ответ

2 голосов
/ 01 июня 2019

Самый простой способ - использовать двоичный ввод-вывод для всего. Таким образом, нам не нужно беспокоиться о переключении режимов файлов на полпути, и в 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" и читаем одну «строку», которая охватывает всю текстовую часть. Это предполагает, что текстовая часть достаточно мала, чтобы удобно помещаться в памяти. Остальная часть сценария такая же.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...