Protobuf流媒体(懒惰序列化)API



我们有一个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();

在其他协议 - 缓冲器版本中可能有可能进行某些内容

最新更新