使用Java 8

时间:2016-01-22 06:38:20

标签: java file split java-8 nio

我是Java 8的新手,我刚开始使用NIO包进行文件处理。我需要帮助处理大型文件 - 每个文件从100,000行到1,000,000行 - 通过将每行转换为特定格式并将格式化的行写入新文件。生成的新文件每个文件最多只能包含100,000行。所以:

  • 如果我有一个500,000行的文件进行处理,我必须转换它们 在5个新文件中分配和打印它们。
  • 如果我有一个745,000行的文件进行处理,我必须转换它们 在8个新文件上打印并打印出来。

我很难找到能够有效利用Java 8新功能的方法。我已经开始根据大文件的行数来确定要生成的新文件的数量,然后创建这些新的空文件:

Path largFile = Path.get("path\to\file");
long recordCount = Files.lines(file).count();
int maxRecordOfNewFiles = 100000;
int numberOfNewFiles =  1;
if (recordCount > maxRecordOfNewFiles) {
    numberOfNewFiles = Math.toIntExact(recordCount / maxRecordOfNewFiles);
if (Math.toIntExact(recordCount % maxRecordOfNewFiles) > 0) {
    numberOfNewFiles ++;
}
}

IntStream.rangeClosed(1, numberOfNewFiles).forEach((i) 
    -> {
        try {
            Path newFile = Paths.get("path\to\newFiles\newFile1.txt");
                        Files.createFile(cdpFile);
         } catch (IOException iOex) {
         }
        });

但是当我浏览largeFileFiles.lines(largeFile).forEach(())能力的行时,我迷失了如何继续格式化前100,000行,然后确定第一个新文件和将它们打印在该文件上,然后将第二批100,000打印到第二个新文件,依此类推。

任何帮助将不胜感激。 :)

2 个答案:

答案 0 :(得分:3)

当你开始构思批处理时,我认为你应该考虑使用专门的框架。您可能希望处理重新启动,安排... Spring Batch非常适合并且已经提供了您想要的内容:MultiResourceItemWriter写入多个文件,每个文件的最大行数为FlatFileItemReader从文件中读取数据。

在这种情况下,您想要的是循环输入文件的每一行,并在多个输出文件中写入每行的转换。

这样做的一种方法是在输入文件的行上创建一个Stream,映射每一行并将其发送到自定义编写器。当自定义编写器达到每个文件的最大行数时,它将实现切换编写器的逻辑。

在以下代码MyWriter中,为文件打开BufferedWriter。当达到maxLines(其倍数)时,将关闭此编写器并打开另一个编写器,递增currentFile。这样,我们写入多个文件对读者来说是透明的。

public static void main(String[] args) throws IOException {
    try (
        MyWriter writer = new MyWriter(10);
        Stream<String> lines = Files.lines(Paths.get("path/to/file"));
    ) {
        lines.map(l -> /* do transformation here */ l).forEach(writer::write);
    }
}

private static class MyWriter implements AutoCloseable {

    private long count = 0, currentFile = 1, maxLines = 0;
    private BufferedWriter bw = null;

    public MyWriter(long maxLines) {
        this.maxLines = maxLines;
    }

    public void write(String line) {
        try {
            if (count % maxLines == 0) {
                close();
                bw = Files.newBufferedWriter(Paths.get("path/to/newFiles/newFile" + currentFile++ + ".txt"));
            }
            bw.write(line);
            bw.newLine();
            count++;
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    @Override
    public void close() throws IOException {
        if (bw != null) bw.close();
    }
}

答案 1 :(得分:2)

据我的理解。一个简单的方法可以是:

BufferedReader buff = new BufferedReader(new FileReader(new File("H:\\Docs\\log.txt")));
Pair<Integer, BufferedWriter> ans = buff.lines().reduce(new Pair<Integer, BufferedWriter>(0, null), (count, line) -> {
    try {
        BufferedWriter w;
        if (count.getKey() % 1000 == 0) {
            if (count.getValue() != null) count.getValue().close();
            w = new BufferedWriter(new FileWriter(new File("f" + count.getKey() + ".txt")));
        } else w = count.getValue();
        w.write(line + "\n"); //do something
        return new Pair<>(count.getKey() + 1, w);
    } catch (IOException e) {
        throw new UncheckedIOException(e);
    }
}, (x, y) -> {
    throw new RuntimeException("Not supproted");
});
ans.getValue().close();