ファイルへの書き込みはそれほど難しくありません。かなり簡単に思えます。
あなたが思っているほど簡単ではありません。ファイルの内容を確認するか、書いている内容を印刷してみてください。
>>> struct.pack('<s', 'myapp-0.0.1')
'm'
ドキュメントが説明しているように:
フォーマット文字の場合's'
、カウントは文字列のサイズとして解釈され、他のフォーマット文字のような繰り返しカウントではありません。たとえば、'10s'
は単一の 10 バイト文字列を'10c'
意味し、 は 10 文字を意味します。カウントが指定されていない場合、デフォルトは 1 です。
それで、あなたはこれにどのように対処しますか?
必要ない場合は使用しないでくださいstruct
。使用する主な理由は、Cオブジェクトをバッファ/ファイル/ソケット/その他に直接struct
ダンプする C コード、または同様のスタイルで記述されたバイナリ形式仕様 (IP ヘッダーなど) とやり取りすることです。struct
これは、Python データの一般的なシリアル化を目的としたものではありません。Jon Clements がコメントで指摘しているように、保存したいのが文字列だけwrite
の場合は、そのままの文字列です。もっと複雑なものを保存したい場合は、json
モジュールを検討してください。さらに柔軟で強力なものが必要な場合は、 を使用してpickle
ください。
固定長の文字列を使用します。ファイル形式の仕様で、名前を常に 255 文字以下にする必要がある場合は、'<255s'
. 短い文字列はパディングされ、長い文字列は切り捨てられます (静かに切り捨てるのではなく、例外を発生させるためにチェックを入れることをお勧めします)。
長さに沿って通過する帯域内または帯域外の手段を使用します。最も一般的なのは、長さのプレフィックスです。('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')
1
infile
'm'
'm'
特定のユース ケース (「コンテンツに関する情報、バージョン情報、およびその他の文字列値を含むファイル ヘッダー…」) ではwrite
、文字列に改行ターミネータを使用するだけです。(文字列に改行を埋め込むことができる場合は、それらをバックスラッシュでエスケープして\n
、C スタイルまたは RFC822 スタイルの継続を使用し、それらを引用することができます。)
これには多くの利点があります。1 つは、フォーマットを簡単に人間が読めるようにする (そして人間が編集可能/デバッグ可能にする) ことです。また、これにはスペースのトレードオフが伴う場合もありますが、1 文字のターミネータは、少なくとも長さプレフィックス形式よりも効率的であり、おそらくそれ以上です。最後になりましたが、これは、コードがヘッダーの生成と解析の両方で非常に単純であることを意味します。
後のコメントで、int も書きたいと明確にしていますが、何も変わりません。'i'
int 値は 4 バイトかかりますが、ほとんどのアプリは多数の小さな数値を書き込みます。これらの数値を文字列として書き込むと、1 ~ 2 バイト (ターミネーター/セパレーターの場合は +1) しかかかりません。また、小さな数値を書き込んでいない場合、Pythonint
は簡単に大きすぎて C に収まらない可能性があります。int
その場合struct
、暗黙のうちにオーバーフローし、下位 32 ビットだけを書き込みます。