2014-08-28 43 views
4

我想將包含字符串的大文件合併到一個文件中,並嘗試使用nio2。我不想加載整個文件到內存中,所以我的BufferedReader試了一下:合併大文件而不將整個文件加載到內存中?

public void mergeFiles(filesToBeMerged) throws IOException{ 

Path mergedFile = Paths.get("mergedFile"); 
Files.createFile(mergedFile); 

List<Path> _filesToBeMerged = filesToBeMerged; 

try (BufferedWriter writer = Files.newBufferedWriter(mergedFile,StandardOpenOption.APPEND)) { 
     for (Path file : _filesToBeMerged) { 
// this does not work as write()-method does not accept a BufferedReader 
      writer.append(Files.newBufferedReader(file)); 
     } 
    } catch (IOException e) { 
     System.err.println(e); 
    } 

} 

我這個試了一下,這個工作,豪爾,該字符串的格式(例如,新線等不復制到合併文件):

... 
try (BufferedWriter writer = Files.newBufferedWriter(mergedFile,StandardOpenOption.APPEND)) { 
     for (Path file : _filesToBeMerged) { 
//    writer.write(Files.newBufferedReader(file)); 
      String line = null; 


BufferedReader reader = Files.newBufferedReader(file); 
      while ((line = reader.readLine()) != null) { 
        writer.append(line); 
        writer.append(System.lineSeparator()); 
      } 
reader.close(); 
     } 
    } catch (IOException e) { 
     System.err.println(e); 
    } 
... 

如何在不將整個文件加載到內存的情況下將大文件與NIO2合併?

回答

13

如果你想合併兩個或更多的文件,你應該問自己,爲什麼地球上你使用char爲基礎的ReaderWriter來執行該任務。

通過使用這些類,您可以將文件字節轉換爲字符,從系統的默認編碼轉換爲unicode,然後從unicode轉換回系統的默認編碼。這意味着程序必須對整個文件執行兩次數據轉換。

而且,順便說一下,BufferedReaderBufferedWriter決不是NIO2 artifacts。這些類自Java的第一個版本開始就存在。

當您使用通過實時NIO功能逐字節複製,文件可以不通過Java應用程序被感動被轉移時,在轉移將直接在文件系統中的緩衝液中進行最好的情況是:

import static java.nio.file.StandardOpenOption.*; 

import java.io.IOException; 
import java.nio.channels.FileChannel; 
import java.nio.file.Path; 
import java.nio.file.Paths; 

public class MergeFiles 
{ 
    public static void main(String[] arg) throws IOException { 
    if(arg.length<2) { 
     System.err.println("Syntax: infiles... outfile"); 
     System.exit(1); 
    } 
    Path outFile=Paths.get(arg[arg.length-1]); 
    System.out.println("TO "+outFile); 
    try(FileChannel out=FileChannel.open(outFile, CREATE, WRITE)) { 
     for(int ix=0, n=arg.length-1; ix<n; ix++) { 
     Path inFile=Paths.get(arg[ix]); 
     System.out.println(inFile+"..."); 
     try(FileChannel in=FileChannel.open(inFile, READ)) { 
      for(long p=0, l=in.size(); p<l;) 
      p+=in.transferTo(p, l-p, out); 
     } 
     } 
    } 
    System.out.println("DONE."); 
    } 
} 
+0

哇,這個解決方案真的很棒 - 源代碼太短了。謝謝!你知道一個基於nio2的解決方案將一個大文件分割成一組較小的文件嗎?其實,我正在使用類似http://todayguesswhat.blogspot.de/2014/05/java-split-large-file-sample-code-high.html。 – nimo23 2014-08-28 12:52:58

+0

@ nimo23:好吧,我想,當你試着理解我的答案的代碼,尤其是['FileChannel.transferTo'](http://docs.oracle.com/javase/7/docs/api/java/ nio/channels/FileChannel.html#transferTo(long,%20long,%20java.nio.channels.WritableByteChannel)),你會意識到分裂的解決方案看起來是怎樣的(閱讀:非常相似)。如果您在實施時遇到困難,您可以打開一個新問題。 – Holger 2014-08-28 13:40:25

+0

好的,我會自己試試,並會在這裏提供解決方案! – nimo23 2014-08-28 13:46:39

2

隨着

Files.newBufferedReader(file).readLine() 

您創建一個新的緩衝每次連帶總是在第一線復位。

完成時

BufferedReader reader = Files.newBufferedReader(file); 
while ((line = reader.readLine()) != null) { 
    writer.write(line); 
} 

.close()讀者替換。

+0

謝謝,我對源代碼進行了修改。你知道嗎,我怎樣才能將合併文件的格式保存到「mergedFile」文件中?例如,合併的文件具有回車符或空白行。當使用上面的方法時,所有這些都不會被複制到「mergedFile」中。 – nimo23 2014-08-28 11:00:35

+0

不確定你的意思,但你可以使用writer.write(System.lineSeparator())手動追加新行; – 2014-08-28 11:01:55

+0

是的,現在它工作。我改變了上面的來源。 – nimo23 2014-08-28 11:09:51

1

readLine()不會產生行尾(「\ n」或「\ r \ n」)。那是錯誤。

while ((line = reader.readLine()) != null) { 
    writer.write(line); 
    writer.write("\r\n"); // Windows 
} 

您也可以忽略的(可能不同)行尾此過濾,並使用

try (OutputStream out = new FileOutputStream(file); 
    for (Path source : filesToBeMerged) { 
     Files.copy(path, out); 
     out.write("\r\n".getBytes(StandardCharsets.US_ASCII)); 
    } 
} 

這明確地寫一個換行符,在的情況下,最後一行不換行結束。

可選的醜陋Unicode BOM字符在文件開頭標記爲UTF-8/UTF-16LE/UTF-16BE可能仍存在問題。

相關問題