2016-08-23 9 views
0

私はdictオブジェクトの大きなリストを持っています。このリストをtarファイルに保存して、リモートで交換したいと思います。私は、 'w:gz'モードで開いたtarfileオブジェクトにjson.dumps()文字列を書き込むことで成功しました。JSONを直接tarファイルにダンプする

「w | gz」モードでtarfileオブジェクトを開くと、パイプで実装しようとしています。これまでのコードはこれまで通りです:

from json import dump 
from io import StringIO 
import tarfile 

with StringIO() as out_stream, tarfile.open(filename, 'w|gz', out_stream) as tar_file: 
    for packet in json_io_format(data): 
     dump(packet, out_stream) 

このコードは関数 'write_data'にあります。 'json_io_format'は、データセットから一度に1つのdictオブジェクトを返すジェネレータです(パケットはdictです)。ここで

は私のエラーです:コメントから助けを借りて、いくつかのトラブルシューティングの後

Traceback (most recent call last): 
    File "pdml_parser.py", line 35, in write_data 
    dump(packet, out_stream) 
    File "/.../anaconda3/lib/python3.5/tarfile.py", line 2397, in __exit__ 
    self.close() 
    File "/.../anaconda3/lib/python3.5/tarfile.py", line 1733, in close 
    self.fileobj.close() 
    File "/.../anaconda3/lib/python3.5/tarfile.py", line 459, in close 
    self.fileobj.write(self.buf) 
TypeError: string argument expected, got 'bytes' 

、エラーがときのステートメントが終了「と」引き起こし、およびコンテキストマネージャの__exit__を呼び出そうとしています。 I BELIEVEこれは次にTarFile.close()を呼び出します。私は声明「と」からtarfile.open()の呼び出しを削除し、意図的TarFile.close()省略した場合、私はこのコードを取得する:

with StringIO() as out_stream: 
    tarfile.open(filename, 'w|gz', out_stream) as tar_file: 
    for packet in json_io_format(data): 
     dump(packet, out_stream) 

プログラムのこのバージョンが完了するのではなく、出力ファイル「filname」を生成し、このエラーを得られます。

Exception ignored in: <bound method _Stream.__del__ of <targile._Stream object at 0x7fca7a352b00>> 
Traceback (most recent call last): 
    File "/.../anaconda3/lib/python3.5/tarfile.py", line 411, in __del__ 
    self.close() 
    File "/.../anaconda3/lib/python3.5/tarfile.py", line 459, in close 
    self.fileobj.write(self.buf) 
TypeError: string argument expected, got 'bytes' 

私はそれがガベージコレクタによって引き起こされると考えています。何かがTarFileオブジェクトが閉じないようにしています。

誰でも私がここで何が起こっているのか理解できますか?

+1

あなたの例外はループの途中ではなく、 'with'ブロックの最後(ループの最後の後)にあります。 'tarfile'コンテキストマネージャーへの' __close__'呼び出しは、私が完全に理解していない何らかの方法でデータに問題があります(これは答えではなくコメントです)。デバッグを簡単にするために、ループなしで1つの値を単にダンプするだけでテストできます。 – Blckknght

+0

tarfile宣言をwith文から削除する関数を書き直して、同じエラーが発生しました。 tar_file.close()を削除しました。ガベージコレクタがストリームオブジェクトを削除しようとすると、エラーが発生します。そう、はい、tarfileを閉じることに何か問題があります。私はこれを反映するために、私の質問を修正します、チップのおかげで。 – kingledion

答えて

1

なぜあなたはStringIOにtarファイルを書き込むことができると思いますか?あなたがそう思っているようには動作しません。

このアプローチではエラーは発生しませんが、メモリ内のオブジェクトからメモリにtarfileを作成する方法は実際にはありません。

from json import dumps                
from io import BytesIO              
import tarfile                  

data = [{'foo': 'bar'},                
     {'cheese': None},                
     ]                    

filename = 'fnord'                 
with BytesIO() as out_stream, tarfile.open(filename, 'w|gz', out_stream) as tar_file: 
    for packet in data:                
     out_stream.write(dumps(packet).encode())          
+0

私がしようとしていたのは、StringIOを使ってtarfileを満たすことでした。パイプを使ってこれをやりたかったので、データを処理してパイプを介してこのスクリプトに渡しました。このスクリプトはjson形式のデータをtarファイルに送ります。今は毎回タールファイルをまとめて送信します。私はあなたの答えから印象を得ています。私が実際にやっているのは、tarファイルを出力ストリームに送ることです。私はそれをどうやってやっているのか分かりません。 – kingledion

+0

あなたは 'piped manner'と言っても、実際に' in memory'を意味しますか?それらは2つの異なるものですから、後者をしようとしているように見えます。もしあなたが* By *しようとしているのは、BytesIOを使っているのと同じように、tarファイルを作成することです。なぜなら、tarファイルはバイナリであるからです!次は、有効なJSONファイルではない複数のJSONデータを含む単一のファイルを使用するか、またはtarに多数のJSONファイルを必要とするかによって異なります。a)1つのファイルを開き、それが十分に大きくなったら、それをタールして送信するか、b)データの各チャンクに対してファイルを開く –

関連する問題