将字节数组转储到文件中时进行解码和编码

时间:2019-04-22 09:43:36

标签: json python-3.x

下面是我在扫描DynamoDb表时得到的响应,诸如此类(数据的较短版本)。

{'id': {'S': '123'}, 'applicationName': {'S': 'swagger_petstore_1_0_0_mock_app'}, 'endpointIds': {'SS': ['hzl3ns24gzh6egwsltoaa7z4llvc3wq2']}, 'configDetails': {'S': '{"propertyPrefix":"","properties":[],"propertyOverrides":[]}'}, 'description': {'S': 'This is a sample server Petstore server.  You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).  For this sample, you can use the api key `special-key` to test the authorization filters.'}, 'fullyQualifiedDockerImageUrl': {'S': 'R2-6-0.unified-managers.internal.tibco.com:5000/icyxmnf4ayukqsnylrs35spraggw3q27/4uv75dk6m6mg52xrezprwvq7w4x23i7t:1550829818352'}, 'lastModifiedBy': {'S': '3xxyd4szt62rop4npspdrihr5ufyjtwq'}, 'desiredInstanceCount': {'N': '1'}, 'appType': {'S': 'api-mock-app'}, 'version': {'S': '1.0'}, 'isSampleApp': {'N': '0'}, 'endpointBeansBytes': {'B': b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x00\xed[\xebo\xdb8\x12\xffW\x08\xef}\xb8\x05\x1c;\xaf\xb6@pw\xb8\xb4i\x0f\xc1v\xdb\xa0i\xee\xf6\x90\x04]F\xa2mn%Q!\xa98n\x90\xff\xfdf\x86\xd4\xc3\xb6$\xcbY\xa7M\x0f\xfd\x92X|\x0eg~\xf3\xe2\xe3\xfc\xae\'\xc3\xdeAo\xf2%|\x19\x03U\x15\xd2\xa1\xc1\x8f\x97N\xb2\xf2\xd2\t\xf8\xfe?\xa8\xb4CVa?\x00\x00'}}

以便将其写入文件系统。

我已经做到了。

with open("backup.json", "w+") as f:
                f.write(json.dumps(response, indent=JSON_INDENT, default=str))

请注意,我使用了默认的解码方法(因为EndpointBeansBytes不能json可序列化)。

但是当我以这种方式(尝试几种方式)加载此数据时:

1)json.load(open(backup.json)) 我能够读取endpointBeansBytes,但它与我们备份的数据不同。

2)使用此转换数据。

endpointBeansBytes['B'] = str.encode(endpointBeansBytes['B']) 仍然不是相同的数据。

3)endpointBeansBytes['B'] = endpointBeansBytes['B'].encode('utf-8') 仍然不是相同的数据。

我的问题是

1)json.dump默认使用哪种解码方法?

2)为了对第1步中的数据进行编码,需要做什么?

3)我可以使用其他一些解码/编码代替json.dump提供的默认解码/编码,以便不丢失数据的真实性。

1 个答案:

答案 0 :(得分:0)

由于JSON不支持二进制数据,因此必须将二进制编码为字符串形式。在您的情况下,似乎二进制值由'B'键表示。

将二进制数据转换为字符串的常见方法是base64编码。

import json, base64, copy

response = {
    'id': {'S': '123'}, 
    'desiredInstanceCount': {'N': '1'},
    'isSampleApp': {'N': '0'},
    'endpointBeansBytes': {'B': b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x00\xed...'}
}

# --- saving ---------------------------------------------------------------
backup = copy.deepcopy(response)

for val in backup.values():
    if list(val)[0] == 'B':
        val['B'] = base64.b64encode(val['B']).decode('ascii')

with open("backup.json", "w+") as f:
    json.dump(backup, f, indent=2)

# --- restoring ------------------------------------------------------------
with open("backup.json", "r") as f:
    restore = json.load(f)

for val in restore.values():
    if list(val)[0] == 'B':
        val['B'] = base64.b64decode(val['B'].encode('ascii'))

print(response)
print(restore)

注意:

  • json.dump()json.load()直接向文件对象写入/从文件对象读取
  • base64.b64encode() still 会为您提供字节,但是这些字节都在ASCII范围内,可以安全地使用.decode('ascii')转换为字符串。
  • 读取是镜像操作-使用.encode('ascii')将base64字符串转换为字节,然后通过base64.b64decode()恢复原始字节。
  • 我正在使用deepcopy,所以我不会修改原始数据。
  • default的{​​{1}}参数或自定义json.dump都不适合此任务,因为它是必要的上下文(“对象只有一个名为{{ 1}}“ )不能被那些人看到。他们只看到价值本身。它们适用于JSON编码,因为当输入值为JSONEncoder时很明显,但是它们不适用于JSON解码,因为不清楚哪个输入字符串应该被base64解码,以及哪个输入字符串是应该一个人呆着。换句话说,不能保证将 base64可解码的每个字符串都解码。