0

我有大量的 dict 对象。我想将此列表存储在 tar 文件中以进行远程交换。我通过将 json.dumps() 字符串写入以“w:gz”模式打开的 tarfile 对象成功地做到了这一点。

我正在尝试管道实现,以“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' 是一个生成器,它一次从数据集中返回一个 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'

在评论的帮助下进行了一些故障排除后,当“with”语句退出并尝试调用上下文管理器 __exit__ 时会导致错误。我相信这反过来会调用 TarFile.close()。如果我从“with”语句中删除 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 对象关闭。

谁能帮我弄清楚这里发生了什么?

4

1 回答 1

2

为什么您认为可以将 tarfile 写入 StringIO?这不像你想象的那样有效。

这种方法不会出错,但实际上并不是从内存中的对象在内存中创建 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())                                     
于 2016-08-23T20:26:33.993 回答