我们有一个Android应用程序,该应用程序使用协议缓冲器存储应用程序数据。数据格式(大致)是一个单一的Protobuf("容器"),其中包含Protobufs("项目")作为重复字段的列表:
message Container {
repeated Item item = 1;
}
当我们想将更改保存到项目时,我们必须重新创建Protobuf容器,将所有项目添加到它,然后序列化并将其写入文件。
一种方法的问题是,它可能会将保存时使用的内存增加三倍到文件流。
我们想要的是一种创建我们的Protobuf容器并懒惰地将其序列化的方法将所有项目保存在内存中,直到我们在内存中创建整个容器为止。
是否有一种方法可以构建Protobuf并懒洋洋地将其序列化到流?
如果没有办法进行正式执行此操作,是否有任何可以提供帮助的库?有人有任何建议或想法如何以其他方式解决这个问题?替代数据格式或技术(例如JSON或XML包含Protobufs)将使之成为可能?
用于序列化:
ProtoBuf是一种辅助格式,单个项目为合并,重复的项目附加
因此,要将序列写为懒惰的流,您需要做的就是反复编写相同的结构,其中只有一个项目:序列化一个200 x"带有1个项目的容器"的序列,与100%相同序列化1 x"带有200个项目的容器"。
so:只要这样做!
供应:
即从技术上讲非常容易将其读成流 - 但是,这一切都归结为您正在使用的库。例如,我将其公示在Protobuf-net(.NET/C#实现)中为Serializer.DeserializeItems<T>
,它基于您在您描述的表单中读取(完全懒惰/流)类型T
的消息序列问题(因此Serializer.DeserializeItems<Item>
将是取代Serializer.Deserialize<Container>
的流方式 - Protobuf中最外面的对象确实不存在)
如果不可用,但是您可以访问RAW Reader API,您需要做的是:
- 读取一个标题的一个varint-这将是值10(0x0a),即(1&lt;&lt;&lt; 3)| 2"对于场合数(1)和电线类型(2) - 因此,这也可以用短语:"从流中读取单个字节,然后检查值是10"
- 阅读以下项目长度的一个varint
- 现在:
- 如果读取器API允许您限制要处理的最大字节数,请使用此长度来指定以下长度
- 或用长度限制流包装流API,仅限于该长度
- 或只是手动读取许多字节,并从有效载荷构建内存流
- 冲洗,重复
没有这样的东西。原始布夫是一个包装的结构。为了有效地执行此操作,它将需要所有数据。您将必须自己添加"流协议"。也许每个n个项目发送Protobuf msg。
在正常的Java版本的协议缓冲区中,有一个划界文件,您一次编写一个协议屏障。我不确定它是否在Android版本中
aLocation.writeDelimitedTo(out);
正如马克所指出的那样,它很容易实施;只需写一个长度序列化字节。在普通(非Android)Java版本的Protocol-Buffers中,您也可以执行(您必须序列化到字节数组或类似的内容)
private CodedOutputStream codedStream = null;
public void write(byte[] bytes) throws IOException {
if (bytes != ConstClass.EMPTY_BYTE_ARRAY) {
codedStream.writeRawVarint32(bytes.length);
codedStream.writeRawBytes(bytes);
codedStream.flush();
}
}
和
private CodedInputStream coded;
public byte[] read() throws IOException {
if (coded == null) {
throw new IOException("Reader has not been opened !!!");
}
if (coded.isAtEnd()) {
return null;
}
return coded.readBytes().toByteArray();
在其他协议 - 缓冲器版本中可能有可能进行某些内容