【问题标题】:Dumping JSON directly into a tarfile将 JSON 直接转储到 tar 文件中
【发布时间】:2016-08-23 19:22:37
【问题描述】:

我有一个很大的 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'

在 cmets 的帮助下进行了一些故障排除后,当 '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 对象关闭。

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

【问题讨论】:

  • 您的异常不是在循环期间发生,而是在 with 块的末尾(循环结束后)。对tarfile 上下文管理器的__close__ 调用以某种我不完全理解的方式存在数据问题(因此这是评论而不是答案)。为了简化调试,您或许可以通过 dumping 一个不带循环的值进行测试。
  • 我重新编写了函数以从 with 语句中删除 tarfile 声明并得到相同的错误。我删除了 tar_file.close() ,现在当垃圾收集器尝试删除流对象时出现错误。所以是的,tarfile 关闭有问题。我将修改我的问题以反映这一点,感谢您的提示。

标签: python json python-3.x tarfile


【解决方案1】:

为什么您认为可以将 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())                                     

【讨论】:

  • 我试图做的是使用 StringIO 来填充 tarfile。我想以管道方式执行此操作,以便我处理数据并通过管道将其提供给此脚本,而此脚本会将 json 格式的数据提供给 tar 文件。时不时地,我会将 tar 文件打包并发送出去。我从您的回答中得到的印象是,我实际上正在做的是将 tarfile 发送到输出流中。我不明白我是怎么做到的。
  • 当你说piped manner时,你真的是指in memory吗?因为这是两件不同的事情,而且它看起来就像你正在尝试做后者。如果是这种情况,您想要 要做的是创建一个 tar 文件,就像我对 BytesIO 所做的那样,因为嘿,tar 文件是二进制的!你接下来做什么取决于你是想要一个包含一堆 JSON 数据的文件(这不是一个有效的 JSON 文件),还是你的 tar.xml 文件中想要一堆 JSON 文件。您可以a)打开一个文件,当它变得足够大时,将其打包并发送出去,或者b)为每个数据块打开一个文件
猜你喜欢
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 2022-12-16
  • 2012-06-09
  • 1970-01-01
  • 2021-01-17
  • 2014-08-28
  • 1970-01-01
相关资源
最近更新 更多