Как я могу получить доступ к энному байту двоичного скаляра в Perl?

Можно также использовать операторы обратной галочки ('), подобный Perl:

directoryListing = `ls /`
puts directoryListing # prints the contents of the root directory

Удобный, если Вам нужно что-то простое.

то, Какой метод Вы хотите использовать, зависит от точно, что Вы пытаетесь выполнить; проверьте документы на большее количество деталей о различных методах.

5
задан 14 revs, 4 users 99% 18 October 2012 в 18:56
поделиться

5 ответов

Поскольку у вас уже есть содержимое файла в $ thisByteData, вы можете использовать pack / unpack для доступа к n-му байту.

sub getNthByte {
  my ($pos) = @_;
  return unpack("x$pos b1", $thisByteData);
}

#x$pos - treats $pos bytes as null bytes(effectively skipping over them) 
#b1    - returns the next byte as a bit string

Читать в документации пакета, чтобы получить представление о параметрах, которые можно использовать в шаблоне для получения различных возвращаемых значений.

РЕДАКТИРОВАТЬ - Ваш комментарий ниже показывает, что вам не хватает старшего полубайта ('f') первого байта. Я не уверен, почему это происходит, но вот альтернативный метод, который работает, а пока я более подробно изучу поведение распаковки.

sub getNthByte {
  my ($pos) = @_;
  return unpack("x[$pos]H2", $binData);
}

(my $hex = unpack("H*", $binData)) =~ s/(..)/$1 /g;
#To convert the entire data in one go

Используя это, вывод для первых четырех байтов - 0xff 0xd8 0xff 0xe0, который соответствует документации .

3
ответ дан 18 December 2019 в 09:52
поделиться

] Если у вас есть данные в строке и вы хотите перейти к определенному байту, используйте substr , пока вы обрабатываете строку как байты, с которых нужно начинать.

Однако вы можете читать это прямо из файла, без всей этой строковой ерунды, которой люди забивают вам голову. :) Откройте файл с помощью sysopen и правильных опций, используйте seek , чтобы попасть туда, куда хотите, и прочтите, что вам нужно, с помощью sysread .

Вы пропускаете все обходные пути для вещей, которые open и readline пытаются сделать за вас. Если вы просто собираетесь отключить все их функции, даже не используйте их.

8
ответ дан 18 December 2019 в 09:52
поделиться

Я думаю, что правильный ответ включает упаковку / распаковку, но это также может сработать:

use bytes;
while( $bytestring =~ /(.)/g ){
   my $byte = $1;
   ...
}

«использовать байты» гарантирует, что вы никогда не увидите символы, но если у вас есть строка символов и обрабатывая его как байты, вы что-то делаете не так. Внутренняя кодировка символов Perl не определена, поэтому данные, которые вы видите в строке в разделе «использовать байты», почти бессмысленны.

3
ответ дан 18 December 2019 в 09:52
поделиться

Встроенная переменная Perl $ / (или $ INPUT_RECORD_SEPARATOR , если вы используете ing English ) управляет идеей Perl о «линии». По умолчанию он установлен на "\ n" , поэтому строки разделяются символами новой строки (да), но вы можете изменить это на любую другую строку. Или измените его на ссылку на число:

$/ = \1;
while(<FILE>) {
  # read file
}

Установка его на ссылку на число сообщит Perl, что «строка» - это это количество байтов.

Итак, что именно вы пытаетесь сделать? Вероятно, есть несколько модулей, которые будут делать то, что вы пытаетесь сделать, и, возможно, более эффективно. Если вы просто пытаетесь научиться это делать, продолжайте, но если у вас есть конкретная задача, подумайте о том, чтобы не изобретать колесо (если вы этого не хотите).

РЕДАКТИРОВАТЬ: Спасибо jrockway в комментариях ...

Если у вас есть данные Unicode, они могут читать не один байт, а один символ, но если это произойдет, вы сможете использовать байты; чтобы включить отключена автоматическая трансляция байтов в символы.

Теперь вы говорите, что хотите прочитать все данные сразу, а затем передать их функции. Давайте сделаем это:

my $data;
{
  local $/;
  $data = <FILE>;
}

Или это:

my $data = join("", <FILE>);

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

use bytes;

...

my @data = split(//, join("", <FILE>));

А затем у нас есть массив байтов, который мы можем передать функции. Нравится?

вы говорите, что хотите прочитать все данные сразу, а затем передать их функции. Давайте сделаем это:

my $data;
{
  local $/;
  $data = <FILE>;
}

Или это:

my $data = join("", <FILE>);

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

use bytes;

...

my @data = split(//, join("", <FILE>));

А затем у нас есть массив байтов, который мы можем передать функции. Нравится?

вы говорите, что хотите прочитать все данные сразу, а затем передать их функции. Давайте сделаем это:

my $data;
{
  local $/;
  $data = <FILE>;
}

Или это:

my $data = join("", <FILE>);

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

use bytes;

...

my @data = split(//, join("", <FILE>));

А затем у нас есть массив байтов, который мы можем передать функции. Нравится?

2
ответ дан 18 December 2019 в 09:52
поделиться

Не зная больше о том, что вы пытаетесь сделать со своими данными, что-то вроде этого будет перебирать байты в файле:

open(SOURCE, "wl.jpg");
my $byte;
while(read SOURCE, $byte, 1) {
    # Do something with the contents of $byte
}
close SOURCE;

Будьте осторожны с объединением, используемым в вашем примере ; вы можете получить преобразование новой строки, что определенно не то, чего вы хотите при чтении двоичных файлов. (Также неэффективно постоянно расширять скаляр во время его чтения.) Это идиоматический способ преобразовать весь файл в скаляр Perl:

open(SOURCE, "<", "wl.jpg");
local $/ = undef;
my $big_binary_data = <SOURCE>;
close SOURCE;
1
ответ дан 18 December 2019 в 09:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: