2012-01-19 3 views
2

У меня возникла проблема с написанием скрипта Perl для чтения двоичного файла.Как читать двоичный файл в 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; 
     } 
    } 
} 

Я изменил свой код, чтобы он выглядел как показано ниже. Теперь я могу прочитать $ data. Спасибо J-16 SDiZ за указание на это. Я пытаюсь вытолкнуть информацию, полученную из двоичного файла, в массив под названием «@array», думая, чтобы grep-данные из массива для строки соответствовали «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; 
    } 
} 

Опять же, я изменил свой код следующим образом, но он по-прежнему не работает, как это сделать не в состоянии Grep на «P04» правильно, проверив файл «LOG». Он сделал grep весь файл, включая двоичный, как это: @ @ @ @ @ @ @ @ 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; 
} 
+0

['use autodie'] (http://p3rl.org/autodie) –

+0

Нет такой вещи, как« двоичный формат ». Пожалуйста, уточните. В каком формате находятся файлы?Какие у них есть характеристики, которые заставляют вас называть их «в двоичном формате»? – reinierpost

+0

Он находится в формате .gds. Этот файл может читать в Unix с помощью команды strings. Это было возможно в моем скрипте Perl, но я не смог grep данные, которые я хотел (p04 * здесь, в моем коде). – Grace

ответ

5

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

$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.

+0

Привет J-16 SDiZ, спасибо за ответ. каждый из $ файла находится в двоичном формате, и я хочу, чтобы прочитать eaxh файла, чтобы grep некоторая информация в читаемом формате и дамп в другой файл (который я рассматриваю здесь как пост-обработку). Я хочу выполнить что-то вроде «строк | grep », как в Unix. где является $ file здесь в моем коде. Моя проблема здесь не в том, чтобы прочитать двоичный файл, чтобы я мог продолжить работу с другими вещами. Благодарю. – Grace

5

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

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

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

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

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

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

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

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

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

my $offset = index('myword', $file); 
+0

Привет, Динаноид, спасибо за ваш ответ, я попробовал, но это не сработало для меня. Я попытался изменить свой код, как указано выше (мой собственный код, и он не работал). Кроме того, попробованный код, как показано ниже, он мне тоже не сработал. Можете ли вы указать, где я ошибся? Благодарю. – Grace

+1

На что будет назначен файл $? Массив символов? Строка? Что-то другое? –

0

Я не уверен, что я буду быть в состоянии ответить на вопрос OP точно, но вот некоторые примечания, которые могут быть связаны. (edit: это тот же подход, что и ответ @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 двоичным файлом. Файл имеет размер 13 байтов, как видно из du, из-за конечного \n, добавленного echo (как видно из hexdump).

Теперь давайте посмотрим, что происходит, когда мы пытаемся читать его с оператором <> алмазным perl «s (см также What's the use of <> in 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 Cookbook: Chapter 8, File Contents)

Та же ссылка говорит, что один должен UNDEF входной разделитель записей, \$ (который по умолчанию установлен в \n), для того, чтобы хлебать весь файл. Вы можете захотеть, чтобы это изменение было локальным, поэтому используются скобки и local вместо undef (см. Perl Idioms Explained - 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 вместо этого.

Надеюсь, это кому-то поможет,
Приветствия!