0

コンテンツに関する情報を含むファイルヘッダーを読んでいて、書き込もうとしています。バージョン情報、およびその他の文字列値。

ファイルへの書き込みはそれほど難しくありません。かなり簡単に思えます。

outfile.write(struct.pack('<s', "myapp-0.0.1"))

ただし、別の方法でファイルからヘッダーを読み戻そうとすると、次のようになります。

header_version = struct.unpack('<s', infile.read(struct.calcsize('s')))

次のエラーがスローされます。

struct.error: unpack requires a string argument of length 2

このエラーを修正するにはどうすればよいですか? また、正確に何が失敗しているのでしょうか?

4

1 に答える 1

2

ファイルへの書き込みはそれほど難しくありません。かなり簡単に思えます。

あなたが思っているほど簡単ではありません。ファイルの内容を確認するか、書いている内容を印刷してみてください。

>>> struct.pack('<s', 'myapp-0.0.1')
'm'

ドキュメントが説明しているように:

フォーマット文字の場合's'、カウントは文字列のサイズとして解釈され、他のフォーマット文字のような繰り返しカウントではありません。たとえば、'10s'は単一の 10 バイト文字列を'10c'意味し、 は 10 文字を意味します。カウントが指定されていない場合、デフォルトは 1 です。

それで、あなたはこれにどのように対処しますか?

  1. 必要ない場合は使用しないでくださいstruct。使用する主な理由は、Cオブジェクトをバッファ/ファイル/ソケット/その他に直接structダンプする C コード、または同様のスタイルで記述されたバイナリ形式仕様 (IP ヘッダーなど) とやり取りすることです。structこれは、Python データの一般的なシリアル化を目的としたものではありません。Jon Clements がコメントで指摘しているように、保存したいのが文字列だけwriteの場合は、そのままの文字列です。もっと複雑なものを保存したい場合は、jsonモジュールを検討してください。さらに柔軟で強力なものが必要な場合は、 を使用してpickleください。

  2. 固定長の文字列を使用します。ファイル形式の仕様で、名前を常に 255 文字以下にする必要がある場合は、'<255s'. 短い文字列はパディングされ、長い文字列は切り捨てられます (静かに切り捨てるのではなく、例外を発生させるためにチェックを入れることをお勧めします)。

  3. 長さに沿って通過する帯域内または帯域外の手段を使用します。最も一般的なのは、長さのプレフィックスです。('p'または'P'形式を使用して支援できる場合がありますが、実際には、一致させようとしている C レイアウト/バイナリ形式に依存します。多くの場合、 のような醜いことをしなければなりませんstruct.pack('<h{}s'.format(len(name)), len(name), name)。)


コードが失敗する理由については、複数の理由があります。まず、read(11)11 文字の読み取りが保証されていません。ファイルに 1 文字しかない場合は、それだけで取得できます。第二に、あなたは実際に を呼び出しているのではなく、 を呼び出しているのread(11)です。第三に、あなたのコードが上に示したものと正確に一致していないか、のファイル ポインタが正しい場所にありません。(ここでは Python 2.x を想定しています。3.x ではさらに多くの問題が発生しますが、そこまで問題にはなりませんでした。)read(1)struct.calcsize('s')1infile'm''m'


特定のユース ケース (「コンテンツに関する情報、バージョン情報、およびその他の文字列値を含むファイル ヘッダー…」) ではwrite、文字列に改行ターミネータを使用するだけです。(文字列に改行を埋め込むことができる場合は、それらをバックスラッシュでエスケープして\n、C スタイルまたは RFC822 スタイルの継続を使用し、それらを引用することができます。)

これには多くの利点があります。1 つは、フォーマットを簡単に人間が読めるようにする (そして人間が編集可能/デバッグ可能にする) ことです。また、これにはスペースのトレードオフが伴う場合もありますが、1 文字のターミネータは、少なくとも長さプレフィックス形式よりも効率的であり、おそらくそれ以上です。最後になりましたが、これは、コードがヘッダーの生成と解析の両方で非常に単純であることを意味します。

後のコメントで、int も書きたいと明確にしていますが、何も変わりません。'i'int 値は 4 バイトかかりますが、ほとんどのアプリは多数の小さな数値を書き込みます。これらの数値を文字列として書き込むと、1 ~ 2 バイト (ターミネーター/セパレーターの場合は +1) しかかかりません。また、小さな数値を書き込んでいない場合、Pythonintは簡単に大きすぎて C に収まらない可能性があります。intその場合struct、暗黙のうちにオーバーフローし、下位 32 ビットだけを書き込みます。

于 2013-02-20T01:34:54.573 に答える