如何从java中的一个文件中读取多个protobufs?

时间:2014-11-14 21:27:11

标签: java protocol-buffers

我有一个文件“test.txt”,其中包含每行testMessage.writeDelimitedTo(the-DataOutputStream-that uses a new FileOutputStream pointing to the file)写的多个protobuf“TestMessage”消息。我如何阅读每行test.txt并获取每行的protobuf?

在包含字符串的文件上使用bufferedreader,我会这样做:

String strLine; // What is the alternative to String?
    while ((strLine = br.readLine()) != null)   {
         System.out.println (strLine);
         TestMessage test = new TestMessage.builder();
         test.parseDelimitedFrom(strLine);
    }

如果我要使用此方法,我应该将类型设置为“String”而不是“String”?这有可能吗?

或者我不能这样做,每个mressage必须写入一个单独的文件吗?

注意:假设TestMessage是唯一的消息。

2 个答案:

答案 0 :(得分:5)

为什么每行写一条消息?我想你可以只使用writeDelimitedTo,然后消息可以逐个写。阅读非常简单。

User user = User.newBuilder().setUid(1).build();
User user2 = User.newBuilder().setUid(2).build();
try {
    FileOutputStream output = new FileOutputStream(path);
    user.writeDelimitedTo(output);
    user.writeDelimitedTo(output);
    user2.writeDelimitedTo(output);
    output.close();
} catch (Exception e) {
    System.out.print("Write error!");
}

try {
    FileInputStream input = new FileInputStream(path);
    while (true) {
        User user_ = User.parseDelimitedFrom(input);
        if (user_ == null)
            break;
        System.out.println("read from file: \n" + user_);
    }
} catch (Exception e) {
    System.out.println("Read error!");
}

答案 1 :(得分:0)

Protobufs与行分隔的文本文件没有多少共同之处。 Protobuf用于将对象分成字节。此过程称为序列化。 Protobuf特别注重兼容性和小尺寸。

您遇到的问题是protobufs不存储有关每个对象组成的字节数或每个对象的类型的信息。因此,如果将许多protobuf序列化对象存储到文件中,则无法在不包含有关要遵循的对象类型以及对象的字节数的数据的情况下提取它们。

此数据称为标题。

public void serializeProtobufObject(OutputStream stream, Object obj){
    byte[] bytes = getProtobufBytes(obj);
    int id = getObjectID(obj);

    //write protobuf header info
    writeInt(stream,id);
    writeInt(stream,bytes.length);

    //write protobuf payload
    stream.write(bytes,0,bytes.length);
}

//called repeatedly for many objects in the same stream.
public Object deserializeProtobufObject(InputStream stream){
    //read protobuf header
    int id = readInt(stream);
    int length = readInt(stream);

    //use header to interpret payload
    return readObject(id, length, stream);
}

整数ID将告诉您跟随的对象类型。整数长度告诉您对象的组成字节数。反序列化时,您将使用这两条信息来提取protobuf对象。如果你在同一个流中有很多protobuf对象,你会反复这样做。

这里一个优秀的方法是为这两个字段创建一个Protobuf对象,并将这样的对象序列化到你的流中:

ProtobufHeader for Foo
[Foo]
ProtobufHeader for Bar
[Bar]

这将允许您将来扩展protobuf标头。