Python 3,从/向gzip文件读/写压缩的json对象

Hen*_*ton 27 json gzip python-3.x

对于Python3,我跟着@Martijn Pieters的代码:

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')
Run Code Online (Sandbox Code Playgroud)

但这会导致错误:

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'
Run Code Online (Sandbox Code Playgroud)

关于发生了什么的任何想法?

Tom*_*lak 69

你在这里有四个转变步骤.

  1. Python数据结构(嵌套的dicts,列表,字符串,数字,布尔值)
  2. 包含该数据结构的序列化表示的Python字符串("JSON")
  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.GzipFile(jsonfilename, 'w') as fout:   # 4. gzip
    fout.write(json_bytes)                       
Run Code Online (Sandbox Code Playgroud)

请注意,"\n"这里添加完全是多余的.它不会破坏任何东西,但除此之外它没有任何用处.

阅读完全相反:

with gzip.GzipFile(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)
Run Code Online (Sandbox Code Playgroud)

当然,这些步骤可以合并:

with gzip.GzipFile(jsonfilename, 'w') as fout:
    fout.write(json.dumps(data).encode('utf-8'))                       
Run Code Online (Sandbox Code Playgroud)

with gzip.GzipFile(jsonfilename, 'r') as fin:
    data = json.loads(fin.read().decode('utf-8'))
Run Code Online (Sandbox Code Playgroud)

  • 这有一个事件更紧凑的方法,它可以让gzip处理编码,而json直接使用gzip的流:/sf/answers/3467503091/ (2认同)

Jan*_*rik 21

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

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

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

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

  • “utf-8”编码不是比“ascii”更安全吗?我在这里使用了 ascii,与 /sf/answers/3467503091/ 中的转储代码保持一致。 (3认同)