2013-09-30 22 views
0

我想達到以下效果。番石榴+合併多個文件並跳過重複的標題

假設我們有兩個文件 - 文件1和文件2具有以下內容

文件1:

header 
d1 
d2 

文件2:

header 
d3 
d4 

然後合併後的文件應該是

輸出文件:

header 
d1 
d2 
d3 
d4 

請注意,我們正在跳過第二個文件的標題。我使用Guava在Java中編寫了以下代碼。

LinkedList<InputSupplier<BufferedReader>> listOfSuppliers = 
       new LinkedList<InputSupplier<BufferedReader>>(); 

     boolean firstFile = true; 
     for (Path path : inputPaths) { 

      InputSupplier<BufferedReader> reader = newBufferedReaderSupplier(fs.open(path)); 
      if (!firstFile) { 
       String ignored = reader.getInput().readLine(); 
       LOGGER.info("Ignored header from the second file " + ignored); 
      } 
      listOfSuppliers.add(reader); 
      firstFile = false; 
     } 

     InputSupplier<Reader> combined = CharStreams.join(listOfSuppliers); 
     OutputSupplier<OutputStreamWriter> outputStream 
       = Files.newWriterSupplier(output, Charsets.UTF_8, false); 
     CharStreams.copy(combined, outputStream); 

這段代碼的問題是,當我們跳過標題時,輸出文件沒有來自第二個文件的內容。我認爲BufferedReader正在做一些導致整個文件被忽略的東西。

想法如何解決這個問題?

+0

我對Guava類沒有把握,但來自Java NIO的'Files'有一個'readAllLines'方法,它返回'List '。在每個文件上使用它。清除第二行的第一行並追加兩個列表。然後將它們寫入文件。 –

回答

2

恐怕這一切都是錯誤的。來自InputSupplier.getInput() javadoc:

與Iterable#iterator類似,可以重複調用此方法以獲取獨立通道到相同的基礎資源。

這是你在

String ignored = reader.getInput().readLine(); 

我猜做了什麼,相反,你的InputSupplier不遵守合同。如果確實如此,上述路線將是無效的。此外,它會讓溪流開放。

你從來沒有說你的文件是巨大的,所以閱讀所有的人都通過Files.readLines,手動從所有,但第一除去標題行,和連接是恕我直言,要走的路。


如果您發現它效率低下,請注意最耗時的部分可能是char和back轉換的字節。使用UTF-8(以及許多其他編碼),跳過第一行可以簡單地使用InputStream(請注意BufferedReader將「\ r」,「\ n」或「\ r \ n」中的任意一個視爲行打破)。但要小心root of all evil


雖然供應商設計,以防止資源泄漏,他們有沒有神奇的實現它。這是他們在Byte/CharStreams方法中的用法,它可以確保所有內容都被關閉。