使用Java 8处理和拆分大型文件

使用Java 8处理和拆分大型文件,java,file,split,java-8,nio,Java,File,Split,Java 8,Nio,我是Java8新手,刚刚开始使用NIO包进行文件处理。我需要关于如何处理大型文件(每个文件从100000行到1000000行)的帮助,方法是将每行转换为特定格式,并将格式化的行写入新文件。生成的新文件每个文件最多只能包含100000行。因此: 如果我有一个500000行的文件要处理,我必须转换它们 并在5个新文件上分发和打印它们 如果我有一个745000行文件要处理,我必须转换它们 行并将其打印到8个新文件上 我很难找到一种有效利用Java8新特性的方法。我首先根据大文件的行数确定要生成的新

我是Java8新手,刚刚开始使用NIO包进行文件处理。我需要关于如何处理大型文件(每个文件从100000行到1000000行)的帮助,方法是将每行转换为特定格式,并将格式化的行写入新文件。生成的新文件每个文件最多只能包含100000行。因此:

  • 如果我有一个500000行的文件要处理,我必须转换它们 并在5个新文件上分发和打印它们
  • 如果我有一个745000行文件要处理,我必须转换它们 行并将其打印到8个新文件上
我很难找到一种有效利用Java8新特性的方法。我首先根据大文件的行数确定要生成的新文件数,然后创建这些新的空文件:

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) {
         }
        });
但是当我通过
Files.lines(largeFile).forEach(())
功能查看
largeFile
的行时,我不知道如何继续格式化前100000行,然后确定第一个新文件并在该文件上打印,然后将第二批100000行打印到第二个新文件,等等


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

根据我所了解的情况。一个简单的方法可以是:

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();
BufferedReader buff=new BufferedReader(新文件读取器(新文件(“H:\\Docs\\log.txt”));
Pair ans=buff.lines().reduce(新对(0,null),(计数,行)->{
试一试{
缓冲写入器w;
if(count.getKey()%1000==0){
如果(count.getValue()!=null)count.getValue().close();
w=新的BufferedWriter(新的FileWriter(新文件(“f”+count.getKey()+”.txt”));
}else w=count.getValue();
w、 写(行+“\n”);//做点什么
返回新对(count.getKey()+1,w);
}捕获(IOE异常){
抛出新的未选中异常(e);
}
},(x,y)->{
抛出新的RuntimeException(“不受支持”);
});
ans.getValue().close();

<>代码> 当你开始构思批处理时,我认为你应该考虑使用一个专门的框架。您可能需要处理重新启动、计划。。。这非常好,并且已经提供了您想要的功能:以每个文件最多行的方式写入多个文件,并从文件中读取数据


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

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

在下面的代码中,
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();
    }
}
publicstaticvoidmain(字符串[]args)引发IOException{
试一试(
MyWriter=新MyWriter(10);
streamline=Files.line(path.get(“path/to/file”);
) {
line.map(l->/*在这里进行转换*/l).forEach(writer::write);
}
}
私有静态类MyWriter实现自动关闭{
私有长计数=0,currentFile=1,maxLines=0;
private BufferedWriter bw=null;
公共MyWriter(长maxLines){
this.maxLines=maxLines;
}
公共无效写入(字符串行){
试一试{
如果(计数%maxLines==0){
close();
bw=Files.newufferedwriter(path.get(“path/to/newFiles/newFile”+currentFile++.txt”);
}
写入(行);
换行符();
计数++;
}捕获(IOE异常){
抛出新的未选中异常(e);
}
}
@凌驾
public void close()引发IOException{
如果(bw!=null)bw.close();
}
}

您可以开始读取和格式化每行代码,直到达到100k,然后保存新的零件文件。@WoozyCoder,您好!:)这基本上就是我在文章的最后一部分所说的。哈哈。我的问题是如何使用Java8实现这一点?代码片段将非常有用。:)您可以使用
列表
来存储格式化的数据(但不知道这是什么意思)。当达到100k或文件末尾时,创建零件文件,保存
ArrayList
中包含的数据,然后继续下一行。问题是,到目前为止你尝试了什么?@WoozyCoder尝试了你的想法,它可以处理较小的文件。不过,我不确定大文件会怎么样。我还将尝试Tunaki和Jatin的答案,以测试您的想法中哪一个更快、内存效率更高,因为我将在生产规模的环境中使用它。:)谢谢,@Tunaki!:)我将尝试您的答案,并提供最新信息:)我正在重新考虑使用另一个框架,因为我想尝试一下仅Java8如何解决这个问题。您认为在内存和速度方面,使用Spring批处理比使用Java的本机库更有效吗?:)@BubeyReb严格来说,这不是一个效率问题,SpringBatch只是为批处理过程提供了预构建的工具(您可以将其读入),如事务管理、作业处理统计、作业重启、跳过和资源管理。。。因此,如果这是您想要的(并且您打算编写多个批处理),您可以记住它;)。对于这个简单的例子来说,这肯定是太多了。嗨@Jatin!Java8让我害怕的是它有多复杂,它让像我这样的开发人员很难阅读代码。看看你的答案,是ki