6

我想将包含字符串的大文件合并到一个文件中并尝试使用 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 合并?

4

3 回答 3

19

如果您想有效地合并两个或多个文件,您应该问自己,到底为什么要使用charbasedReaderWriter执行该任务。

通过使用这些类,您可以将文件的字节转换为字符,从系统的默认编码转换为 unicode,然后从 unicode 转换为系统的默认编码。这意味着程序必须对整个文件执行两次数据转换。

而且,顺便说一句,BufferedReader绝不BufferedWriterNIO2人工制品。这些类从 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.");
  }
}
于 2014-08-28T12:13:36.043 回答
3

Files.newBufferedReader(file).readLine()

您每次都创建一个新的缓冲区,它总是在第一行重置。

用。。。来代替

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

.close()读者完成后。

于 2014-08-28T10:45:20.797 回答
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));
    }
}

如果最后一行不以换行符结尾,这将显式写入换行符。

在文件开头将文本标记为 UTF-8/UTF-16LE/UTF-16BE 的可选的、丑陋的 Unicode BOM 字符可能仍然存在问题。

于 2014-08-28T11:09:10.417 回答