序列化消息中的换行符

Jan*_*ger 2 protocol-buffers

一些 protobuf 消息在序列化为字符串时,其中包含换行符\n。通常,当消息的第一个字段是字符串时,在消息之前添加换行符。但是我们也在中间的某个地方发现了带有换行符的消息。

换行符的问题是当您想将消息一行一行地保存到一个文件中时。换行符换行并使消息无效。

示例.proto

syntax = "proto3";

package data_sources;

message StringFirst {
  string key = 1;
  bool valid = 2;
}

message StringSecond {
  bool valid = 1;
  string key = 2;
}
Run Code Online (Sandbox Code Playgroud)

例子.py

from protocol_buffers.data_sources.example_pb2 import StringFirst, StringSecond

print(StringFirst(key='some key').SerializeToString())
print(StringSecond(key='some key').SerializeToString())
Run Code Online (Sandbox Code Playgroud)

输出

b'\n\x08some key'
b'\x12\x08some key'
Run Code Online (Sandbox Code Playgroud)

这是预期/期望的行为吗?如何防止换行符?

Mar*_*ell 5

protobuf 是一个二进制协议(除非你在谈论可选的 json 东西)。所以:任何时候您以任何方式将其视为类似文本的时候,您都在错误地使用它并且行为将是未定义的。这包括担心是否有 CR/LF 字符,但也包括空字符 (0x00) 之类的东西,在许多框架(特别是 C-字符串)。

具体来说:

  • LF (0x0A) 与“field 1, length-prefixed”的字段头相同
  • CR (0x0D) 与“字段 1,固定 32 位”的字段头相同
  • 0x00、0x0A 或 0x0D 中的任何一个都可以作为长度前缀出现(表示长度为 0、10 或 13)
  • 0x00、0x0A 或 0x0D 中的任何一个都可能在二进制数据中自然出现 ( bytes)
  • 0x00、0x0A 或 0x0D 中的任何一个都可以在任何数字类型中自然出现
  • 0x0A 或 0x0D 可能在文本数据中自然出现(如果您的原始框架允许在字符串中任意使用空字符,则 0x00 可能会出现,所以......不是 C 字符串)
  • 可能还有一系列其他事情

所以:再次 - 如果包含“特殊”文本字符有问题:您使用错误

将二进制数据作为文本处理的最常见方法是使用 base-N 编码;base-16(十六进制)便于显示和读取,但就传送相同字节数所需的字符数而言,base-64 更有效。因此,如果可能:根据需要转换为 base-64 或从 base-64 转换。Base-64 从不包含任何不可打印的字符,因此您永远不会遇到 CR/LF/nul。