2010-08-17 2 views
3

Я пытаюсь прочитать двоичный файл со следующим кодом:Проблемы с чтением двоичного файла с помощью ActivePerl?

open(F, "<$file") || die "Can't read $file: $!\n"; 
binmode(F); 
$data = <F>; 
close F; 

open (D,">debug.txt"); 
binmode(D); 
print D $data; 
close D; 

Входной файл 16м; debug.txt - всего около 400 тыс. Когда я смотрю debug.txt в emacs, последние два символа:^A^C (символы SOH и ETX, в соответствии с блокнотом ++), хотя тот же шаблон присутствует в debug.txt. Следующая строка в файле имеет символ^O (SI), и я думаю, что это первое появление этого конкретного символа.

Как читать во всем этом файле?

+0

$ data = ; получает $ data = do {undef $ /; }; –

ответ

5

Если вы действительно хотите, чтобы прочитать весь файл сразу, используйте режим slurp. Режим Slurp можно включить, установив $/ (который является разделителем входных данных) на undef. Это лучше всего сделать в отдельном блоке, чтобы вы не испортили $/ для другого кода.

my $data; 
{ 
    open my $input_handle, '<', $file or die "Cannot open $file for reading: $!\n"; 
    binmode $input_handle; 
    local $/; 
    $data = <$input_handle>; 
    close $input_handle; 
} 

open $output_handle, '>', 'debug.txt' or die "Cannot open debug.txt for writing: $!\n"; 
binmode $output_handle; 
print {$output_handle} $data; 
close $output_handle; 

Использование my $data для лексических и our $data для глобальной переменной.

+1

Под редакцией, чтобы продвигать современные методы, см. Обоснование в [Почему открытые вызовы с тремя аргументами с лексическими файловыми дескрипторами - передовая практика Perl?] (Http://stackoverflow.com/questions/1479741/why-is-three-argument- open-calls-with-lexical-filehandles-a-perl-best-practice) и [Что лучше всего открыть и прочитать файл в Perl?] (http://stackoverflow.com/questions/318789/whats-the -лучший-путь к открытому и-читать-файл-в-Perl). – daxim

+0

@ daxim - Я хотел предложить эту проверку, но я чувствовал, что это была ответственность OP ... :) – MvanGeest

+1

Мы не можем преподавать, не руководствуясь хорошими образцами для подражания и искореняя устаревший код. :) – daxim

3

TIMTOWTDI.

File::Slurp - это кратчайший способ выразить то, что вы хотите достичь. Он также имеет встроенную проверку ошибок.

use File::Slurp qw(read_file write_file); 
my $data = read_file($file, binmode => ':raw'); 
write_file('debug.txt', {binmode => ':raw'}, $data); 

IO::File API решает глобальную переменную $/ проблему более элегантной моды.

use IO::File qw(); 
my $data; 
{ 
    my $input_handle = IO::File->new($file, 'r') or die "could not open $file for reading: $!"; 
    $input_handle->binmode; 
    $input_handle->input_record_separator(undef); 
    $data = $input_handle->getline; 
} 
{ 
    my $output_handle = IO::File->new('debug.txt', 'w') or die "could not open debug.txt for writing: $!"; 
    $output_handle->binmode; 
    $output_handle->print($data); 
} 
+0

Не столько заботясь об элегантности - это быстро и грязное решение, но спасибо за образование. – chris

+0

Во втором примере почему вы локализуете код в блоках? – jmcnamara

+0

Когда переменная дескриптора выходит за пределы области видимости, прикрепленный файловый дескриптор автоматически закрывается. Голый блок - самый простой способ создать такой масштаб. – daxim

0

Я не думаю, что речь идет о режиме slurp или нет, но о правильной обработке двоичных файлов.

вместо

$data = <F>; 

вы должны сделать

read(F, $buffer, 1024); 

Это только для чтения 1024 байт, так что вы должны увеличить буфер или читать весь файл по частям с помощью цикла.