2014-11-14 129 views
-1

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

随着包含字符串文件一个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); 
    } 

什么我设置的类型,而不是“字符串”如果我是这样做的方法?这可能吗?

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

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

+2

您需要使用Java Protocol Buffers API。这不是一个文本文件,你不应该试图逐行读取它。 – 2014-11-14 21:39:08

+0

因此,如果我有10条消息要保存以便在文件中稍后阅读时使用,我应该使用单独的文件吗? – Rolando 2014-11-14 21:43:13

+1

@Rlando不一定。您可以为我的答案中描述的文件中存储的每个对象创建自己的标题。如果你没有时间或倾向来创建自己的标题,那么是的。您必须为每个对象使用单独的文件。 – 2014-11-14 21:46:10

回答

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!"); 
} 
+2

你应该更多地解释你的答案。只是发布可行的代码不会帮助其他有类似问题的人。 – mhlz 2015-04-14 12:28:16

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会告诉你什么类型的对象是跟随。整数长度表示对象由多少个字节组成。当您反序列化时,您将使用这2条信息来提取protobuf对象。如果在同一个流中有许多protobuf对象,您将重复执行此操作。这里

优越的方法是创建这些2个字段的Protobuf对象和序列化对象,像这样你流:

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

这将允许你扩大你的protobuf头的未来。

+0

“readObject”是如何工作的?既然你不能逐行阅读它的接缝。每个文件都“附加”到我正在使用的一个文件的新行中。 – Rolando 2014-11-14 22:07:32

+0

ReadObject从流中提取'length'字节,并尝试使用protobuf的读例程读取映射到整数类型id的对象。 也抛出了新行作为某种与protobufs分隔符的概念。新行在protobuf中没有任何意义。 – 2014-11-14 22:18:11

+0

我期待能够将每个字节的字节写成文本,然后将它们读回到对象中。 – Rolando 2014-11-14 22:25:55

相关问题