【问题标题】:Python 3, read/write compressed json objects from/to gzip filePython 3,从/向 gzip 文件读/写压缩的 json 对象
【发布时间】:2017-01-19 21:02:19
【问题描述】:

对于 Python3,我关注了 @Martijn Pieters's code

import gzip
import json

# writing
with gzip.GzipFile(jsonfilename, 'w') as fout:
    for i in range(N):
        uid = "whatever%i" % i
        dv = [1, 2, 3]
        data = json.dumps({
            'what': uid,
            'where': dv})

        fout.write(data + '\n')

但这会导致错误:

Traceback (most recent call last):
    ...
  File "C:\Users\Think\my_json.py", line 118, in write_json
    fout.write(data + '\n')
  File "C:\Users\Think\Anaconda3\lib\gzip.py", line 258, in write
    data = memoryview(data)
TypeError: memoryview: a bytes-like object is required, not 'str'

有什么想法吗?

【问题讨论】:

  • 这段代码可能是用python2编写的。尝试对数据进行编码:(data+'\n').encode('utf-8').
  • @Bakuriu 不,同样的错误。

标签: json python-3.x gzip


【解决方案1】:

这里有四个转换步骤。

  1. Python 数据结构(嵌套字典、列表、字符串、数字、布尔值)
  2. 包含该数据结构(“JSON”)的序列化表示的 Python 字符串
  3. 包含该字符串(“UTF-8”)表示的字节列表
  4. 包含前一个字节列表(“gzip”)的更短表示的字节列表

那么让我们一步一步来。

import gzip
import json

data = []
for i in range(N):
    uid = "whatever%i" % i
    dv = [1, 2, 3]
    data.append({
        'what': uid,
        'where': dv
    })                                           # 1. data

json_str = json.dumps(data) + "\n"               # 2. string (i.e. JSON)
json_bytes = json_str.encode('utf-8')            # 3. bytes (i.e. UTF-8)

with gzip.open(jsonfilename, 'w') as fout:       # 4. fewer bytes (i.e. gzip)
    fout.write(json_bytes)                       

请注意,在这里添加"\n" 完全是多余的。它不会破坏任何东西,但除此之外它没有任何用处。我添加它只是因为您的代码示例中有它。

阅读正好相反:

with gzip.open(jsonfilename, 'r') as fin:        # 4. gzip
    json_bytes = fin.read()                      # 3. bytes (i.e. UTF-8)

json_str = json_bytes.decode('utf-8')            # 2. string (i.e. JSON)
data = json.loads(json_str)                      # 1. data

print(data)

当然可以合并步骤:

with gzip.open(jsonfilename, 'w') as fout:
    fout.write(json.dumps(data).encode('utf-8'))                       

with gzip.open(jsonfilename, 'r') as fin:
    data = json.loads(fin.read().decode('utf-8'))

【讨论】:

  • 多么棒的周到的答案。现在可以了。谢谢!
  • 哎呀。对不起。点赞!我猜大多数人(包括我)认为接受答案会自动投赞成票。 SO应该是这样设置的。附言。不要个人认为。
  • 我不是个人。我只是每次都在挠头。赞成+不接受:“这很有帮助,另一个答案更好一点” - 赞成+接受“这很有帮助,它解决了我的问题。” - 不赞成 + 接受“这并不是我真正想要的,但我会使用它,因为缺乏替代品” - 不赞成 + 接受 + 热情评论:[不计算]。 :D
  • 这有一个事件更紧凑的方法,让 gzip 处理编码和 json 直接使用来自 gzip 的流:stackoverflow.com/a/49535758/1236083
  • @greenie-beans 无论json.dumps 做什么都与gzip 无关。我建议制作一个简短的代码示例(只有代码的json 部分,没有其他内容)重现您看到的错误,并将其作为一个独立的问题提出。
【解决方案2】:

提到的解决方案here(感谢@Rafe)有一个很大的优势:由于编码是即时完成的,因此您不会创建生成的 json 的两个完整的中间字符串对象。对于大对象,这可以节省内存。

with gzip.open(jsonfilename, 'wt', encoding='UTF-8') as zipfile:
    json.dump(data, zipfile)

另外,读取和解码也很简单:

with gzip.open(jsonfilename, 'rt', encoding='UTF-8') as zipfile:
    my_object = json.load(zipfile)

【讨论】:

  • utf-8 编码不是比ascii 更安全的选择吗?我在这里使用了 ascii,以符合 stackoverflow.com/a/49535758/1236083 中的转储代码。
  • 我同意UTF-8,所以我们继续编辑你的答案
  • 这应该是公认的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-06
  • 1970-01-01
  • 1970-01-01
  • 2021-11-15
  • 1970-01-01
  • 2010-10-12
  • 1970-01-01
相关资源
最近更新 更多