7

我们正在考虑使用 Protocol Buffers 进行二进制日志记录,因为:

  • 无论如何,这就是我们编码对象的方式
  • 它相对紧凑,读/写速度快等。

也就是说,我们应该如何去做并不明显,因为 API 倾向于专注于创建整个对象,因此将 DataLogEntry 列表包装为 DataLogFile 中的重复字段将是您在消息传递方面所做的事情,但是我们真正想要的只是能够写入然后读取整个 DataLogEntry,将其附加到文件的末尾。

我们这样做遇到的第一个问题是这样做(在测试中:

        FileInputStream fileIn = new FileInputStream(logFile);
        CodedInputStream in = CodedInputStream.newInstance(fileIn);
        while(!in.isAtEnd()) {
            DataLogEntry entry = DataLogEntry.parseFrom(in);
            // ... do stuff
        }

只会导致从流中读取 1 个 DataLogEntry。没有 isAtEnd,它永远不会停止。

想法?

编辑:我已经切换到使用 entry.writeDelimitedTo 和 BidLogEntry.parseDelimitedFrom ,这似乎工作......

4

2 回答 2

4

根据我对协议缓冲区的理解,它不支持单个流中的多个消息。因此,您可能需要自己跟踪消息的边界。您可以通过在日志中每条消息之前存储消息的大小来做到这一点。

public class DataLog {

    public void write(final DataOutputStream out, final DataLogEntry entry) throws IOException {
        out.writeInt(entry.getSerializedSize());
        CodedOutputStream codedOut = CodedOutputStream.newInstance(out);
        entry.writeTo(codedOut);
        codedOut.flush();
    }

    public void read(final DataInputStream in) throws IOException {
        byte[] buffer = new byte[4096];
        while (true) {
            try {
                int size = in.readInt();
                CodedInputStream codedIn;
                if (size <= buffer.length) {
                    in.read(buffer, 0, size);
                    codedIn = CodedInputStream.newInstance(buffer, 0, size);
                } else {
                    byte[] tmp = new byte[size];
                    in.read(tmp);
                    codedIn = CodedInputStream.newInstance(tmp);
                }
                DataLogEntry.parseFrom(codedIn);
                // ... do stuff
            }
            catch (final EOFException e) {
                break;
            }
        }
    }
}

注意:我使用 EOFException 来查找文件结尾,您可能希望使用分隔符或手动跟踪读取的字节数。

于 2010-03-10T22:02:26.870 回答
4

至少从 2.4.0a 开始,这很容易。使用 writeDelimitedTo 编写您的消息。无需直接使用编码流。

于 2011-04-10T11:48:32.640 回答