【问题标题】:Write protobuf objects to JSON file将 protobuf 对象写入 JSON 文件
【发布时间】:2021-09-29 00:17:38
【问题描述】:

我有这样的old.JSON 文件:

[{
    "id": "333333",
    "creation_timestamp": 0,
    "type": "MEDICAL",
    "owner": "MED.com",
    "datafiles": ["stomach.data", "heart.data"]
}]

然后我根据.proto文件创建一个对象:

message Dataset {
  string id = 1;
  uint64 creation_timestamp = 2;
  string type = 3;
  string owner = 4;
  repeated string datafiles = 6;
}

现在我想保存这个对象,将这个对象保存回其他.JSON 文件。 我这样做了:

import json
from google.protobuf.json_format import MessageToJson

with open("new.json", 'w') as jsfile:
    json.dump(MessageToJson(item), jsfile)

结果我有:

"{\n  \"id\": \"333333\",\n  \"type\": \"MEDICAL\",\n  \"owner\": \"MED.com\",\n  \"datafiles\": [\n    \"stomach.data\",\n    \"heart.data\"\n  ]\n}"

如何使这个文件看起来像old.JSON 文件?

【问题讨论】:

  • 这与原作有何不同?我注意到它不在列表中。是这个问题吗?
  • @tdelaney 是的,它不是一个列表。它有 \" 而不仅仅是 ",并且 \n 是显式的。
  • 你试过直接jsfile.write(MessageToJson(item))吗?
  • 该列表可能是您最初保存数据的方式。您为列表中的单个 dict 定义了消息类型。根据您在此处发布的内容,我不知道您是否为封闭列表定义了另一种消息类型。但是,如果您只是对该外部列表的每个项目进行编码,您就会丢失该列表。至于\n,请尝试打印字符串...它们会呈现为换行符。字符串的 python 表示形式将它们显示为 \n,以便您可以看到它们。
  • @Psidom 有效,但另存为非列表,但我可以手动将[] 添加到文件中。

标签: python json protocol-buffers


【解决方案1】:

奇怪的转义来自两次将文本转换为 json,从而迫使第二次调用从第一次调用中转义 json 字符。详细解释如下:

https://developers.google.com/protocol-buffers/docs/reference/python/google.protobuf.json_format-pysrc

31  """Contains routines for printing protocol messages in JSON format. 
32   
33  Simple usage example: 
34   
35    # Create a proto object and serialize it to a json format string. 
36    message = my_proto_pb2.MyMessage(foo='bar') 
37    json_string = json_format.MessageToJson(message) 
38   
39    # Parse a json format string to proto object. 
40    message = json_format.Parse(json_string, my_proto_pb2.MyMessage()) 
41  """ 

还有

 89 -def MessageToJson(message, including_default_value_fields=False): 
...
 99    Returns: 
100      A string containing the JSON formatted protocol buffer message. 

很明显,这个函数将返回一个字符串类型的对象。这个字符串包含了很多json结构,但是对于python来说,它仍然只是一个字符串。

然后将它传递给一个函数,该函数接受一个 python 对象(不是 json),并将其序列化为 json。

https://docs.python.org/3/library/json.html

json.dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)

Serialize obj as a JSON formatted stream to fp (a .write()-supporting file-like object) using this conversion table.

好的,您将如何将字符串编码为 json?显然它不能只使用 json 特定的字符,所以这些字符必须被转义。也许有一个在线工具,比如http://bernhardhaeussner.de/odd/json-escape/http://www.freeformatter.com/json-escape.html

你可以去那里,从你的问题顶部发布起始 json,告诉它生成正确的 json,然后你回来......几乎正是你在问题底部得到的。很酷,一切正常!

(我说几乎是因为其中一个链接自己添加了一些换行符,没有明显的原因。如果您使用第一个链接对其进行编码,然后使用第二个链接对其进行解码,则完全正确。)

但这不是您想要的答案,因为您不想对数据结构进行双重 json 化。您只想将其序列化为 json 一次,然后将其写入文件:

import json
from google.protobuf.json_format import MessageToJson

with open("new.json", 'w') as jsfile:
    actual_json_text = MessageToJson(item)
    jsfile.write( actual_json_text )

附录:MessageToJson 可能需要其他参数才能按预期运行
包括_default_value_fields=真
preserve_proto_field_name=真
(参见下面的 cmets 和链接)

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-18
  • 1970-01-01
  • 2017-06-29
  • 1970-01-01
  • 2018-07-14
  • 2021-05-20
相关资源
最近更新 更多