我们有一个Android应用程序,它使用Protocol Buffers来存储应用程序数据。数据格式(粗略地)是单个protobuf(“容器”),其包含作为重复字段的protobufs(“items”)列表:
message Container {
repeated Item item = 1;
}
当我们想要保存对项目的更改时,我们必须重新创建protobuf容器,将所有项目添加到其中,然后将其序列化并将其写入文件。
这种方法的问题是它可能使保存时使用的内存增加三倍,因为数据必须首先从模型类复制到protobuf构建器,然后在protobuf序列化时复制到字节数组,所有这些都在写入之前到文件流。
我们想要的是一种创建我们的protobuf容器并将其懒惰地序列化为流的方法,然后简单地将每个protobuf项(从我们的模型数据创建)添加到容器中,该容器序列化并将其写入流,而不是保留所有项目,直到我们在内存中创建整个容器。
有没有办法构建一个protobuf并将其懒洋洋地序列化为流?
如果没有办法正式执行此操作,是否有任何图书馆可以提供帮助?有没有人有任何建议或想法如何以其他方式解决这个问题?替代数据格式或技术(例如JSON或包含protobufs的XML)可以实现这一目标吗?
答案 0 :(得分:3)
序列化:
protobuf是一种可附加格式,单个项目合并,重复项目追加
因此,要将序列编写为惰性流,您需要做的就是重复编写相同的结构,列表中只有一个项目:序列化200 x“Container with 1 Item”的序列与100%完全相同序列化1 x“有200个项目的容器”。
所以:就这样做!
反序列化:
技术上非常容易作为流阅读 - 然而,这一切都归结为您正在使用的库。例如,我在protobuf-net(一个.NET / C#实现)中将其公开为Serializer.DeserializeItems<T>
,它基于以下假设读取(完全延迟/流式传输)T
类型的消息序列。它们采用您在问题中描述的形式(因此Serializer.DeserializeItems<Item>
将是替换Serializer.Deserialize<Container>
的流媒体方式 - 最外层的对象有点并不存在于protobuf中)
如果这不可用,但您可以访问原始阅读器API,那么您需要做的是:
答案 1 :(得分:0)
没有这样的事情。 protobuf是一种包装结构。为了有效地做到这一点,它将需要所有数据。您将不得不添加&#34;流媒体协议&#34;你自己。也许每N个项目发送一个protobuf消息。
答案 2 :(得分:0)
在协议缓冲区的普通java版本中,存在一个分隔文件,您可以在其中一次编写一个协议缓冲区。我不确定它是否在Android版本
aLocation.writeDelimitedTo(out);
正如马克所说,它很容易实施;然后写一个长度 序列化的字节。在正常(非机器人)java版本的prortocol-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();
其他协议缓冲区版本中可能存在某些内容