Как читать бинарный файл в Perl - PullRequest
4 голосов
/ 19 января 2012

У меня проблема с написанием сценария Perl для чтения двоичного файла.

Мой код следующий: $file - это файлы в двоичном формате.Я пытался искать в Интернете и применять в своем коде, пытался распечатать его, но кажется, что он не работает хорошо.

В настоящее время он печатает только '&&&&&&&&&&& "и" "ppppppppppp", ночто я действительно хочу, так это то, что он может распечатать каждый из $line, чтобы позже я мог выполнить некоторую другую постобработку.Кроме того, я не совсем уверен, что такое $data, так как я вижу, что оно является частью кода из примера в статье, утверждая, что это скаляр.Мне нужен кто-то, кто может указать мне, где ошибка идет не так в моем коде.Ниже я сделал то, что сделал.

my $tmp = "$basedir/$key";
opendir (TEMP1, "$tmp");
my @dirs = readdir(TEMP1);
closedir(TEMP1);

foreach my $dirs (@dirs) {
    next if ($dirs eq "." || $dirs eq "..");
    print "---->$dirs\n";
    my $d = "$basedir/$key/$dirs";
    if (-d "$d") {
        opendir (TEMP2, $d) || die $!;
        my @files = readdir (TEMP2); # This should read binary files
        closedir (TEMP2);

        #my $buffer = "";
        #opendir (FILE, $d) || die $!;
        #binmode (FILE);
        #my @files =  readdir (FILE, $buffer, 169108570);
        #closedir (FILE);

        foreach my $file (@files) {
            next if ($file eq "." || $file eq "..");
            my $f = "$d/$file";
            print "==>$file\n";
            open FILE, $file || die $!;
            binmode FILE;
            foreach ($line = read (FILE, $data, 169108570)) {
                print "&&&&&&&&&&&$line\n";
                print "ppppppppppp$data\n";
            }
            close FILE;
        }
    }
}

Я изменил свой код так, чтобы он выглядел так, как показано ниже.Теперь я могу читать данные в $.Спасибо J-16 SDiZ за указание на это.Я пытаюсь перенести информацию, полученную из двоичного файла, в массив с именем «@array», пытаясь получить данные из массива для поиска строки, которая соответствует «p04», но не получается.Может кто-нибудь указать, где находится ошибка?

my $tmp = "$basedir/$key";
opendir (TEMP1, "$tmp");
my @dirs = readdir (TEMP1);
closedir (TEMP1);

foreach my $dirs (@dirs) {
    next if ($dirs eq "." || $dirs eq "..");
    print "---->$dirs\n";
    my $d = "$basedir/$key/$dirs";
    if (-d "$d") {
        opendir (TEMP2, $d) || die $!;
        my @files = readdir (TEMP2); #This should read binary files
        closedir (TEMP2);

        foreach my $file (@files) {
            next if ($file eq "." || $file eq "..");
            my $f = "$d/$file";
            print "==>$file\n";
            open FILE, $file || die $!;
            binmode FILE;
            foreach ($line = read (FILE, $data, 169108570)) {
                print "&&&&&&&&&&&$line\n";
                print "ppppppppppp$data\n";
                push @array, $data;
            }
            close FILE;
        }
    }
}

foreach $item (@array) {
    #print "==>$item<==\n"; # It prints out content of binary file without the ==> and <== if I uncomment this.. weird!
    if ($item =~ /p04(.*)/) {
        print "=>$item<===============\n"; # It prints "=><===============" according to the number of binary file I have.  This is wrong that I aspect it to print the content of each binary file instead :(
        next if ($item !~ /^w+/);
        open (LOG, ">log") or die $!;
        #print LOG $item;
        close LOG;
    }
}

Опять же, я изменил свой код следующим образом, но он по-прежнему не работает, так как не может корректно отобразить "p04", проверив"журнальный файл.Это действительно grep весь файл, включая двоичный файл, как это "@ ^ @ ^ @ ^ @ ^ G ^ D ^ @ ^ @ ^ @ ^^ @ p04bbhi06 ^ @ ^^ @ ^ @ ^ @ ^ @ ^ @ ^ @ ^ @ ^@ hh ^ R ^ @ ^ @ ^ @ ^^ @ ^ @ ^ @ p04lohhj09 ^ @ ^ @ ^ @ ^^ @@ ".То, что я аспектирую, это то, что он делает grep что-нибудь только с p04, например, grepping p04bbhi06 и p04lohhj09.Вот как работает мой код: -

foreach my $file (@files) {
    next if ($file eq "." || $file eq "..");
    my $f = "$d/$file";
    print "==>$file\n";
    open FILE, $f || die $!;
    binmode FILE;
    my @lines = <FILE>;
    close FILE;
    foreach $cell (@lines) {
        if ($cell =~ /b12/) {
            push @array, $cell;
        }
    }
}

#my @matches = grep /p04/, @lines;
#foreach $item (@matches) {
foreach $item (@array) {
    #print "-->$item<--";
    open (LOG, ">log") or die $!;
    print LOG $item;
    close LOG;
}

Ответы [ 3 ]

7 голосов
/ 19 января 2012

Использование:

$line = read (FILE, $data, 169108570);

Данные в $data; $line - количество прочитанных байтов.

       my $f = "$d/$file" ;
       print "==>$file\n" ;
       open FILE, $file || die $! ;

Полагаю, полный путь указан в $f, но вы открываете $file. (В моем тестировании - даже $f не полный путь, но я думаю, у вас может быть какой-то другой клейкий код ...)

Если вы просто хотите просмотреть все файлы в каталоге, попробуйте File::DirWalk или File::Find.

5 голосов
/ 20 января 2012

Я не уверен, правильно ли я вас понял.

Если вам нужно прочитать двоичный файл, вы можете сделать то же самое, что и для текстового файла:

open F, "/bin/bash";
my $file = do { local $/; <F> };
close F;

Под Windowsвам может понадобиться добавить binmode F; в * nix, он работает без него.

Если вам нужно найти, какие строки в массиве содержат какое-то слово, вы можете использовать функцию grep:

my @matches = grep /something/, @array_to_grep;

Вы получите все совпадающие строки в новом массиве @matches.

Кстати: я не думаю, что будет хорошей идеей читать тонны двоичных файлов впамять сразу.Вы можете искать их 1 на 1 ...

Если вам нужно найти , где совпадение, вы можете использовать другую стандартную функцию, index:

my $offset = index('myword', $file);
0 голосов
/ 18 апреля 2014

Я не уверен, что смогу точно ответить на вопрос ОП, но вот некоторые примечания, которые могут быть связаны. (редактировать: это тот же подход, что и ответ @Dimanoid, но с более подробной информацией)

Скажем, у вас есть файл, который представляет собой смесь данных ASCII и двоичного файла. Вот пример для терминала bash:

$ echo -e "aa aa\x00\x0abb bb" | tee tester.txt
aa aa
bb bb
$ du -b tester.txt 
13  tester.txt
$ hexdump -C tester.txt 
00000000  61 61 20 61 61 00 0a 62  62 20 62 62 0a           |aa aa..bb bb.|
0000000d

Обратите внимание, что байт 00 (указанный как \x00) является непечатаемым символом (а в C он также означает «конец строки») - таким образом, его присутствие делает tester.txt a двоичный файл. Файл имеет размер 13 байт, как видно из du, из-за завершающего \n, добавленного echo (как видно из hexdump).

Теперь давайте посмотрим, что произойдет, когда мы попытаемся прочитать его с помощью оператора perl diamond * (см. Также Какая польза от <> в perl? ):

$ perl -e '
open IN, "<./tester.txt";
binmode(IN);
$data = <IN>; # does this slurp entire file in one go?
close(IN);
print "length is: " . length($data) . "\n";
print "data is: --$data--\n";
'

length is: 7
data is: --aa aa
--

Очевидно, что весь файл не был захвачен - он сломался в конце строки \n (а не в двоичном \x00). Это связано с тем, что оператор <FH> для алмазного файла на самом деле является ярлыком для readline (см. Руководство по Perl: Глава 8, Содержимое файла )

Эта же ссылка говорит о том, что необходимо отменить разделитель входной записи, \$ (который по умолчанию установлен на \n), чтобы удалить весь файл. Возможно, вы захотите, чтобы это изменение было только локальным, поэтому вместо undef используются скобки и local (см. Объяснения идиом Perl - my $ string = do {local $ /;}; ); итак имеем:

$ perl -e '
open IN, "<./tester.txt";
print "_$/_\n"; # check if $/ is \n
binmode(IN);
{
local $/; # undef $/; is global
$data = <IN>; # this should slurp one go now
};
print "_$/_\n"; # check again if $/ is \n
close(IN);
print "length is: " . length($data) . "\n";
print "data is: --$data--\n";
'

_
_
_
_
length is: 13
data is: --aa aa
bb bb
--

... и теперь мы можем видеть, что файл захвачен полностью.

Поскольку двоичные данные содержат непечатаемые символы, вы можете проверить фактическое содержимое $data, напечатав вместо этого sprintf или pack / unpack.

Надеюсь, это кому-нибудь поможет,
Ура!

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