python pickle loadをシーケンス化し、BytesIO(ファイルストリーム、stream)から値を連続的に取得する(getvalue()

3541 ワード

以前のプロジェクトでpickleのシーケンス化とBytesiOのファイルストリームに触れたことがあります.結局今日問題があったファイルpickledumpがBytesIOに入った後、逆に取り出すことができません..長い間調べてみたら、たくさんの資料が紹介されているような気がします..BytesIOがpickleを利用してすべてを読み上げる操作は何編もありません.
役に立つものをいくつか貼ります.
https://stackoverflow.com/questions/30199393/how-can-pickled-byte-data-be-unpickled
https://stackoverflow.com/questions/53485708/how-the-write-read-and-getvalue-methods-of-python-io-bytesio-work
この記事:https://www.twle.cn/t/452
比較的詳細ですが、BytesIOとpickleの組み合わせによる連続読み書きのファイルストリーム操作についてお話ししました.まさに私が必要としています.
 
私のpickleシーケンス化に対する理解はPythonの任意のオブジェクトを話して、例えばクラス、実力、リスト、辞書などはバイナリに変換して、jsonがとても似ていると感じて、違いは1つのバイナリの1つの文字列ですか?
BytesiOは以前は簡単に見たことがありますが、今日彼の機能を見たのはファイルをメモリに書き込むことですか?ファイルストリームのようです.
これは重要ではありません.キーはpickleとBytesiOを組み合わせた読み書きとファイルポインタの位置です.の
まず重点を置いて、私が解決しなければならない問題です.
import pickle,io

io_buffer=io.BytesIO()

pickle.dump('a',io_buffer)
pickle.dump('b',io_buffer)
print(pickle.load(io_buffer))
print(pickle.load(io_buffer))

開始コードはこのように書いて、a,bを出力することができることを期待して、結果は直接間違いを報告します:EOFError:Ran out of input
理由はio_bufferのポインタの位置は最後で、自然とファイルが読めないので、ポインタの位置を最初にリセットする必要があります.コードをこれに変更すればいいです.
pickle.dump('a',io_buffer)
pickle.dump('b',io_buffer)
#      
io_buffer.seek(0)
print(pickle.load(io_buffer))
print(pickle.load(io_buffer))

正常出力:a b
または、BytesiOオブジェクトを再生成します.
pickle.dump('a',io_buffer)
pickle.dump('b',io_buffer)

#    BytesIO  
new_io_buffer=io.BytesIO(io_buffer.getvalue())
# io_buffer.seek(0)
print(pickle.load(new_io_buffer))
print(pickle.load(new_io_buffer))

 
 
なお、getvalue、次のコードgetvalue()は、すべての結果abcを取得することが望ましいが、getvalueで得られた結果resをpickle.loads逆シーケンス化後はaしか得られず,resを直接decodeすることで確実にすべてのabcが得られ,長さ33も3文字の長さであることが証明された.
pickle.dump('a',io_buffer)
pickle.dump('b',io_buffer)
pickle.dump('c',io_buffer)

res=io_buffer.getvalue()
print(res.decode(errors='ignore'))
print(len(res),pickle.loads(res)

出力結果:
X   aq .X   bq .X   cq . 33 a
pickleを使わなければload書き込み、write書き込みでgetvalueは大丈夫で、すべての結果を得ることができます:abc、高人の指摘を求めます...
io_buffer.write(b'a')
io_buffer.write(b'b')
io_buffer.write(b'c')
res=io_buffer.getvalue()
print(len(res),res)

出力結果:
3 b'abc'  
 
 
最後にファイルポインタについてお話しします.主にseekの2つのパラメータです.offset、whence、菜鳥チュートリアルの説明を参照してください.
  • offset--最初のオフセット量、すなわち移動オフセットを表すバイト数
  • whence:オプションで、デフォルトは0です.offsetパラメータを定義し、どの位置からオフセットを開始するかを示します.0はファイルの先頭から、1は現在位置から、2はファイルの末尾からです.
  • io_buffer.write(b'a')
    io_buffer.write(b'b')
    io_buffer.seek(0)
    io_buffer.write(b'c')
    print(io_buffer.getvalue())
    

    このコードがない場合:io_buffer.seek(0)、出力結果はabcであるべきであり、ポインタ位置を開始位置にリセットした後、cはaを上書きするので、出力結果:
    b'cb'
    io_buffer.write(b'a')
    io_buffer.write(b'b')
    
    io_buffer.seek(-1,2)
    io_buffer.write(b'c')
    # print(io_buffer.read())
    print(io_buffer.getvalue())

    io_buffer.seek(-1,2)という文2は最後の位置を表し、-1は前に1つの位置を移動することを表すので、bはcによって出力結果を上書きされる:b'ac'
    io_buffer.write(b'a')
    io_buffer.write(b'b')
    io_buffer.seek(2,2)
    io_buffer.write(b'c')
    # print(io_buffer.read())
    #     
    print(io_buffer.getvalue())
    #     
    print(io_buffer.getvalue().decode())

    io_buffer.seek(2,2)最後の位置を2つ後ろに移動すると、スペースが2つ増え、結果が出力されます.
    b'ab\x00\x00c'
    ab  c
    テストはここまで!