Java 8和文件处理30 MB excel

我的任务之一包括只使用Java 8 ,如果需要,然后只使用Spring ,基本上对这个项目的依赖性最小。

有一个30 MB大小的Excel可以增长。 这通过FTP每天出现,需要处理个别行,然后最终报告需要通过电子邮件发送。

现在我的问题是文件太大,请build议最好的方式来处理它没有任何内存不足的错误。

谢谢

读取文件行的​​标准方式是在内存中 – Guava和Apache Commons IO都提供了一个快速的方法来做到这一点:

Files.readLines(新的文件(path),Charsets.UTF_8);

FileUtils.readLines(new File(path));

这种方法的问题是所有的文件行都保存在内存中 – 如果文件足够大,这将很快导致OutOfMemoryError。

 For example – reading a ~1Gb file: @Test public void givenUsingGuava_whenIteratingAFile_thenWorks() throws IOException { String path = ... Files.readLines(new File(path), Charsets.UTF_8); } 

这从消耗less量内存开始:(〜0 Mb消耗)

 [main] INFO org.baeldung.java.CoreJavaIoUnitTest - Total Memory: 128 Mb [main] INFO org.baeldung.java.CoreJavaIoUnitTest - Free Memory: 116 Mb 

然而,在完整的文件处理完之后,我们最后得到:(消耗2Gb)

 [main] INFO org.baeldung.java.CoreJavaIoUnitTest - Total Memory: 2666 Mb [main] INFO org.baeldung.java.CoreJavaIoUnitTest - Free Memory: 490 Mb 

这意味着大约2.1Gb的内存被这个进程占用 – 原因很简单 – 文件的行全部被存储在内存中。

这一点应该很明显,将文件内容保存在内存中将快速耗尽可用的内存,而不pipe实际上有多less内存。

更重要的是,我们通常不需要同时在内存中的所有行,而只需要遍历每一行,做一些处理并把它扔掉。 所以,这正是我们要做的 – 迭代通过线路,而不是在内存中。

使用Apache Commons IO进行stream式传输

使用Commons IO库也可以实现同样的效果,即使用库提供的自定义LineIterator:

 LineIterator it = FileUtils.lineIterator(theFile, "UTF-8"); try { while (it.hasNext()) { String line = it.nextLine(); // do something with line } } finally { LineIterator.closeQuietly(it); } 

由于整个文件不完全在内存中 – 这也将导致相当保守的内存消耗数量(〜150 Mb消耗)

 [main] INFO objava.CoreJavaIoIntegrationTest - Total Memory: 752 Mb [main] INFO objava.CoreJavaIoIntegrationTest - Free Memory: 564 Mb