2014-11-14 52 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

相關問題