5

事前にみんなに感謝します。

バイナリ スカラーの n 番目のバイトにアクセスしたいと思います。たとえば、すべてのファイル データを 1 つのスカラー変数で取得できます...

バイナリデータがスカラーに収集されると想像してください...

open(SOURCE, "<", "wl.jpg"); 
my $thisByteData = undef; 
while(<SOURCE>){$thisByteData .= $_;} 
close SOURCE; 

$thisByteData は生のバイナリ データです。length($thisByteData) を使用すると、バイト カウントが返されるので、Perl はそれがどのくらい大きいかを認識します。私の質問は、N 番目のバイトにアクセスするにはどうすればよいですか?

補足: 私の関数は、このバイナリ スカラーを受け取ります。この関数では、N 番目のバイトにアクセスしたいと考えています。このデータの収集方法に関するヘルプはありがたいですが、私が探しているものではありません。他のプログラマーがバイナリデータを収集する方法は彼ら次第ですが、私の仕事は、渡されたときに N 番目のバイトを取得することです:)

繰り返しますが、すべての人に助けてくれてありがとう!


これまで以上に私を導いてくれた @muteW に感謝します。unpack(...) を正しく理解していないと思います。

print(unpack("N1", $thisByteData));
print(unpack("x N1", $thisByteData));
print(unpack("x0 N1", $thisByteData));

以下を返します:

4292411360
3640647680
4292411360

これらの 3 行はすべて同じ (最初の) バイトにアクセスすると仮定します。「x」を使用せずに「x」と「x$pos」のみを使用すると、予期しない結果が生じます。

私もこれを試しました...

print(unpack("x0 N1", $thisByteData));
print(unpack("x1 N1", $thisByteData));
print(unpack("x2 N1", $thisByteData));

どちらが返されます...最後のテストと同じもの...

4292411360
3640647680
4292411360

unpack の仕組みについて、間違いなく何かが欠けています。


私がこれをしたら...

print(oct("0x". unpack("x0 H2", $thisByteData)));
print(oct("0x". unpack("x1 H2", $thisByteData)));
print(oct("0x". unpack("x2 H2", $thisByteData)));

私は私が期待していたものを手に入れました...

255
216
255

oct() を使用せずに、これを自分でアンパックできませんか?


補足として、「x$pos N1」を使用すると、これらのバイト整数の 2 の補数を取得していると思います。これらを最初の 3 バイトとして期待しています。

255
216
255

皆様のご協力に改めて感謝いたします。


@brian d foy と @muteW に特に感謝します ... unpack(...) を使用してバイナリ スカラーの N 番目のバイトにアクセスする方法がわかりました。この質問とは関係のない、解決すべき新しい問題があります。もう一度、すべての助けてくれてありがとう!

これにより、望ましい結果が得られました...

print(unpack("x0 C1", $thisByteData));
print(unpack("x1 C1", $thisByteData));
print(unpack("x2 C1", $thisByteData));

unpack(...) にはたくさんのオプションがあるので、これを読んだ人は pack/unpack ドキュメントを読んで、選択したバイトデータの結果を取得することをお勧めします。また、@brian が言及した Tie オプションを使用しようとはしませんでした。コードをできるだけシンプルにしたかったのです。

4

5 に答える 5

8

文字列にデータがあり、特定のバイトに到達したい場合は、最初に文字列をバイトとして扱っている限り、substrを使用します。

ただし、人々が頭をいっぱいにしているこの無意味な文字列をすべて使用せずに、ファイルから直接読み取ることができます。:) sysopenと適切なオプションでファイルを開き、 seekを使用して必要な場所に配置し、 sysreadで必要なものを読み取ります。

があなたのためにやろうとしているopenもののすべての回避策をスキップします。readlineすべての機能をオフにするだけなら、使用しないでください。

于 2009-07-16T23:31:58.253 に答える
3

正しい答えにはパック/アンパックが含まれると思いますが、これもうまくいくかもしれません:

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

「バイトを使用」すると、文字が表示されないことが保証されますが、文字列があり、それをバイトとして処理している場合は、何か問題があります。Perl の内部文字エンコーディングは定義されていないため、"use bytes" の下の文字列に表示されるデータはほとんど意味がありません。

于 2009-07-16T21:40:03.657 に答える
3

$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」) が欠落していることを示しています。なぜこれが起こっているのかはわかりませんが、これが機能する代替方法です。それまでの間、unpack の動作をさらに調べます。

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

これを使用すると、最初の 4 バイトの出力は、ドキュメントと一致する -0xff 0xd8 0xff 0xe0 になります。

于 2009-07-17T04:05:35.800 に答える
2

Perl 組み込み変数$/(またはingの$INPUT_RECORD_SEPARATOR場合は in ) は、Perl の「行」の概念を制御します。デフォルトでは に設定されているため、行は改行文字で区切られていますが(当然)、これを他の文字列に変更できます。または、数値への参照に変更します。useEnglish"\n"

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

数値への参照に設定すると、「行」がそのバイト数であることを Perl に伝えます。

いったい、何をしようとしているのか?おそらく、あなたがしようとしていることを実行し、おそらくより効率的に実行する多くのモジュールがあります。その方法を学びたいだけなら、先に進んでください。ただし、特定のタスクを念頭に置いている場合は、車輪を再発明しないことを検討してください (必要な場合を除きます)。

編集:コメントのjrockwayに感謝...

Unicode データがある場合、これは 1 バイトではなく 1 文字を読み取る可能性がありますが、これが発生した場合は、use bytes;バイトから文字への自動変換をオフにできるはずです。

ここで、データを一度にすべて読み取り、それを関数に渡したいとします。これをやろう:

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

またはこれ:

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

または、モジュールを提案する人もいFile::Slurpますが、それは少しやり過ぎだと思います。ただし、ファイル全体をバイト配列に入れましょう。

use bytes;

...

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

そして、関数に渡すことができるバイトの配列があります。お気に入り?

于 2009-07-16T21:35:02.107 に答える
1

データで何をしようとしているのかについて詳しく知らなくても、次のようなものがファイル内のバイトを反復処理します。

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;
于 2009-07-16T21:35:42.637 に答える