【问题标题】:Serialize in JSON a base64 encoded data在 JSON 中序列化 base64 编码的数据
【发布时间】:2016-05-14 09:35:16
【问题描述】:

我正在编写一个脚本来为演示自动生成数据,我需要在 JSON 中序列化一些数据。此数据的一部分是图像,因此我将其编码为 base64,但是当我尝试运行我的脚本时,我得到:

Traceback (most recent call last):
  File "lazyAutomationScript.py", line 113, in <module>
    json.dump(out_dict, outfile)
  File "/usr/lib/python3.4/json/__init__.py", line 178, in dump
    for chunk in iterable:
  File "/usr/lib/python3.4/json/encoder.py", line 422, in _iterencode
    yield from _iterencode_dict(o, _current_indent_level)
  File "/usr/lib/python3.4/json/encoder.py", line 396, in _iterencode_dict
    yield from chunks
  File "/usr/lib/python3.4/json/encoder.py", line 396, in _iterencode_dict
    yield from chunks
  File "/usr/lib/python3.4/json/encoder.py", line 429, in _iterencode
    o = _default(o)
  File "/usr/lib/python3.4/json/encoder.py", line 173, in default
    raise TypeError(repr(o) + " is not JSON serializable")
  TypeError: b'iVBORw0KGgoAAAANSUhEUgAADWcAABRACAYAAABf7ZytAAAABGdB...
     ...
   BF2jhLaJNmRwAAAAAElFTkSuQmCC' is not JSON serializable

据我所知,base64-encoded-whatever(在本例中为 PNG 图像)只是一个字符串,因此它应该会给序列化带来问题。我错过了什么?

【问题讨论】:

    标签: json python-3.x serialization base64


    【解决方案1】:

    您必须小心数据类型。

    如果你读取二进制图像,你会得到字节。 如果您在 base64 中对这些字节进行编码,您将再次获得 ... 字节! (请参阅b64encode 上的文档)

    json 无法处理原始字节,这就是你得到错误的原因。

    刚刚写了一些例子,用cmets,希望对你有帮助:

    from base64 import b64encode
    from json import dumps
    
    ENCODING = 'utf-8'
    IMAGE_NAME = 'spam.jpg'
    JSON_NAME = 'output.json'
    
    # first: reading the binary stuff
    # note the 'rb' flag
    # result: bytes
    with open(IMAGE_NAME, 'rb') as open_file:
        byte_content = open_file.read()
    
    # second: base64 encode read data
    # result: bytes (again)
    base64_bytes = b64encode(byte_content)
    
    # third: decode these bytes to text
    # result: string (in utf-8)
    base64_string = base64_bytes.decode(ENCODING)
    
    # optional: doing stuff with the data
    # result here: some dict
    raw_data = {IMAGE_NAME: base64_string}
    
    # now: encoding the data to json
    # result: string
    json_data = dumps(raw_data, indent=2)
    
    # finally: writing the json string to disk
    # note the 'w' flag, no 'b' needed as we deal with text here
    with open(JSON_NAME, 'w') as another_open_file:
        another_open_file.write(json_data)
    

    【讨论】:

    • 我在使用 Gmail API 发送具有此特定操作 return {'raw': base64.urlsafe_b64encode(message.as_string())} 的电子邮件时遇到了类似的问题。 @spky 感谢您的回答!
    • 我对excel文件做同样的事情,一切正常,但写入磁盘的文件已损坏,无法正常打开
    • 非常感谢。这让我非常困惑,这很好地解释了它。
    • @spky 在上面我们发送字符串图像。如何再次将该字符串转换回图像
    • @spky 任何想法,如何使用 OpenCV 从这个 json_data 读取图像。
    【解决方案2】:

    另一种解决方案是使用自定义编码器即时编码:

    import json
    from base64 import b64encode
    
    class Base64Encoder(json.JSONEncoder):
        # pylint: disable=method-hidden
        def default(self, o):
            if isinstance(o, bytes):
                return b64encode(o).decode()
            return json.JSONEncoder.default(self, o)
    

    定义好之后你就可以这样做了:

    m = {'key': b'\x9c\x13\xff\x00'}
    json.dumps(m, cls=Base64Encoder)
    

    它将产生:

    '{"key": "nBP/AA=="}'
    

    【讨论】:

      【解决方案3】:

      我错过了什么?

      错误是大喊 binary 不是 JSON 可序列化的。

      from base64 import b64encode
      
      # *binary representation* of the base64 string
      assert b64encode(b"binary content")                 == b'YmluYXJ5IGNvbnRlbnQ='
      
      # base64 string
      assert b64encode(b"binary content").decode('utf-8') ==  'YmluYXJ5IGNvbnRlbnQ='
      

      后者绝对是“JSON 可序列化”,因为它是二进制 b"binary content" 的 base64 字符串表示。

      【讨论】:

      • TypeError: b'...' is not JSON serializable 表示“二进制文件不是 JSON 可序列化的”
      猜你喜欢
      • 2013-05-10
      • 2015-01-29
      • 1970-01-01
      • 2016-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多