pythonのstructにバイナリデータを保存しようとしています。
コードは下記の通りです。
iniHead関数内で、head.passwdにio.BytesIOを用いてバイナリデータを代入しているのですが、\x00で途切れてしまい、データ全てを保存できません。
base64にエンコードすれば、データ全てを保存できるのはわかるのですが、エンコードするとデータサイズが大きくなるのと、余計な処理は追加したくないので、できれば避けたいです。
何か良い方法はありますでしょうか?
python
1from ctypes import * 2import struct 3import io 4import base64 5 6PASS_SIZE = 512 7bin_data = b'\x03\x02\x01\x00\x01\x02\x03' # バイナリデータ 8 9class Head(LittleEndianStructure): 10 _pack_ = 1 11 _fields_ = [ 12 ('id', c_char * 3), 13 ('passwd', c_char * PASS_SIZE), 14 ] 15 16def iniHead(): 17 head = Head() 18 head.id = b'ABC' 19 head.passwd = io.BytesIO(bin_data).read() # バイナリデータを保存 20 return head 21 22if __name__== "__main__": 23 head = iniHead() 24 25 # \x00でデータが途切れてしまう 26 print("head.passwd: {}".format(head.passwd)) # head.passwd: b'\x03\x02\x01' 27 28 # structでなければ、\x00以降も保存される 29 notHeadPasswd = io.BytesIO(bin_data).read() 30 print("notHeadPasswd: {}".format(notHeadPasswd)) # notHeadPasswd: b'\x03\x02\x01\x00\x01\x02\x03' 31 32 # base64にエンコードすれば保存はできる (できれば使いたくない) 33 b64_encode_data = base64.b64encode(bin_data) 34 head.passwd = b64_encode_data 35 b64_decode_data = base64.b64decode(head.passwd) 36 print("b64_decode_data: {}".format(b64_decode_data)) # b64_decode_data: b'\x03\x02\x01\x00\x01\x02\x03' 37
実行結果
head.passwd: b'\x03\x02\x01' notHeadPasswd: b'\x03\x02\x01\x00\x01\x02\x03' b64_decode_data: b'\x03\x02\x01\x00\x01\x02\x03'
structは基本的に固定長で使う物で、もし可変長のデータを扱いたいなら、そのデータを確保したメモリのアドレスへのポインタを持つしかないです。データサイズを気にされていますが、sizeof(head)するとわかりますが現状のコードでは最大長の514バイトが確保されています。
なぜctypeのstructを使いたいのですか?ネットワークやディスクなどからバイト列を読み書きしたいとか、そう言う目的でしょうか?一般に可変長のデータはサイズの情報が先頭にあるか、区切り文字の指定がないと、どれだけ読み込んだら良いのかがわかりません。このあたりの背景が明確になれば解決法はあると思います。\0で切れるのはヌル終端文字列として扱われているからでしょう。
ご助言ありがとうございます。
目的は、バイト列が組み込まれたファイルを読み書きする事です。
そのファイルは、Pythonだけではなく、C言語などのプログラムでも扱える様に互換性を保つ必要があります。
データの内容自体は可変ですが、サイズは固定長です。
なので、
```head.passwd = io.BytesIO(bin_data).read(PASS_SIZE)```
と、読み込むサイズを指定しても問題無いかと思います。(bin_dataはあくまでサンプルで、実際はもっと長いです)
ですがこの様にしても、やはり\x00で途切れてしまいます。
回答1件
あなたの回答
tips
プレビュー