Как записать данные в указанном формате в двоичный файл с помощью Perl?

это может быть вопрос новичка, но мне нужно обработать определенный текстовый файл и сбросить его содержимое в двоичный файл, и я не знаю, как это сделать - я решил использовать Perl, но мои навыки Perl довольно низкие. Вероятно, мне следовало бы написать это на C++, но это кажется хорошей и простой задачей для Perl, так почему бы не изучить что-то новое? ;) Текстовый файл имеет тысячи строк в таком формате:

2A02FC42 4

Вы можете рассматривать его как шестнадцатеричное число (длина ВСЕГДА 8) и обычное число. Теперь мне нужно сбросить все строки в бинарный файл в таком формате (он должен выглядеть так при просмотре в шестнадцатеричном редакторе):

42FC022A00000004

Еще примеры, чтобы было понятно:

70726F67 36 -> 676F727000000024
6A656374 471 -> 7463656A000001D7

Часть синтаксического анализа входного файла проста, но я застрял на второй части, где я должен записать это в двоичный файл. Я понятия не имею, как форматировать данные таким образом или даже как выводить данные в двоичном режиме. Может ли кто-нибудь помочь мне здесь?

Спасибо.

РЕДАКТИРОВАТЬ: обновил примеры, забыл о порядке байтов - я в системе LE.


person PeterK    schedule 19.08.2010    source источник
comment
perldoc.perl.org/functions/pack.html   -  person Sinan Ünür    schedule 19.08.2010


Ответы (3)


Используйте pack:

#! /usr/bin/perl

use warnings;
use strict;

# demo only    
*ARGV = *DATA;

while (<>) {
  my($a,$b) = split;
  $a = join "", reverse $a =~ /(..)/g;
  $b = sprintf "%08x", $b;

  print pack "H*" => $a . $b;
}

__DATA__
2A02FC42 4
70726F67 36
6A656374 471

Пример запуска:

$ ./prog.pl | od -t x1
0000000 42 fc 02 2a 00 00 00 04 67 6f 72 70 00 00 00 24
0000020 74 63 65 6a 00 00 01 d7
0000030
person Greg Bacon    schedule 19.08.2010
comment
Обратите внимание, что для лучшей переносимости вы должны переключать двоичный режим для выходного потока: binmode(STD0UT) - person dolmen; 20.08.2010

Моя версия (проверено):

my $fout;
if ( ! open( $fout, ">/tmp/deleteme.bin" ) ) {
    die( "Failed to open /tmp/deleteme.bin: $!" );
}
binmode( $fout );

while ( <DATA> ) {
    my ( $left, $right ) = split( /\s+/s, $_ );

    my $output = pack( "VN", hex($left), int($right) );
    printf(
        STDERR
        "  note, %8X %d -> " . ( "%02X" x 8 ) . "\n",
        hex($left), $right,
        map { $_ } unpack( "C8", $output )
    );

    print( $fout $output );
}
close( $fout );

__DATA__
70726F67 36 -> 676F727000000024
6A656374 471 -> 7463656A000001D7

выходы:

note, 70726F67 36 -> 676F727000000024
note, 6A656374 471 -> 7463656A000001D7
person PP.    schedule 19.08.2010

Канонический способ - использовать pack. Предположим, что данные, которые вы прочитали из текстового файла, уже преобразованы в числа (в том числе и шестнадцатеричные) и хранятся в переменных $x и $y. Затем вы должны сделать что-то вроде

 print OUTFILE pack("NN", $x, $y);

Если вам нужен другой порядок байтов, вам придется использовать шаблон, отличный от NN, подробности см. в perldoc -f pack.

person Grrrr    schedule 19.08.2010