本教程将演示如何用Java高效地读取大文件. Java——回归基础。
读取文件行的标准方式是在内存中读取,番石榴和ApacheCommonsIO都提供了如下所示快速读取文件行的方法:
<代码>文件。readline(新文件(路径),Charsets.UTF_8); 代码>
<代码> FileUtils。readline(新文件(路径));代码>
这种方法带来的问题是文件的所有行都被存放在内存中,当文件足够大时很快就会导致程序抛出OutOfMemoryError异常。
例如:读取一个大约1克的文件:
@Test 公共空间givenUsingGuava_whenIteratingAFile_thenWorks()抛出IOException { 字符串路径=? 文件。readline(新文件(路径),Charsets.UTF_8); }
这种方式开始时只占用很少的内存:(大约消耗了0 mb内存)
[主要]信息org.baeldung.java。CoreJavaIoUnitTest -总内存:128 Mb [主要]信息org.baeldung.java。CoreJavaIoUnitTest -空闲内存:116 Mb
然而,当文件全部读到内存中后,我们最后可以看到(大约消耗了2 gb内存):
[主要]信息org.baeldung.java。CoreJavaIoUnitTest -总内存:2666 Mb [主要]信息org.baeldung.java。CoreJavaIoUnitTest -空闲内存:490 Mb
这意味这一过程大约耗费了2.1 gb的内存——原因很简单:现在文件的所有行都被存储在内存中。
把文件所有的内容都放在内存中很快会耗尽可用内存,不论实际可用内存有多大,这点是显而易见的。
此外,我们通常不需要把文件的所有行一次性地放入内存中——相反,我们只需要遍历文件的每一行,然后做相应的处理,处理完之后把它扔掉。所以,这正是我们将要做的——通过行迭代,而不是把所有行都放在内存中。
现在让我们看下这种解决方案,我们将使用java.util.Scanner类扫描文件的内容,一行一行连续地读取:
FileInputStream inputStream=零; 扫描仪sc=零; 尝试{ inputStream=new FileInputStream(路径); sc=new扫描仪(inputStream,“utf - 8”); 而(sc.hasNextLine ()) { 字符串行=sc.nextLine ();//System.out.println(线); }//注意,扫描仪抑制异常 如果(sc.ioException () !=null) { 把sc.ioException (); } 最后}{ 如果(inputStream !=null) { inputStream.close (); } 如果(sc !=null) { sc.close (); } }
这种方案将会遍历文件中的所有行——允许对每一行进行处理,而不保持对它的引用。总之没有把它们存放在内存中:(大约消耗了150 mb内存)
[主要]INFOorg.baeldung.java.CoreJavaIoUnitTest-TotalMemory: 763 mb
[主要]INFOorg.baeldung.java.CoreJavaIoUnitTest-FreeMemory: 605 mb
同样也可以使用CommonsIO库实现,利用该库提供的自定义LineIterator:
LineIterator=FileUtils。lineIterator (theFile“utf - 8”); 尝试{ 而(it.hasNext ()) { 字符串行=it.nextLine ();//做一些线 } 最后}{ LineIterator.closeQuietly(它); }
由于整个文件不是全部存放在内存中,这也就导致相当保守的内存消耗:(大约消耗了150 mb内存)
[主要]INFOo.b.java.CoreJavaIoIntegrationTest-TotalMemory: 752 mb
[主要]INFOo.b.java.CoreJavaIoIntegrationTest-FreeMemory: 564 mb
这篇短文介绍了如何在不重复读取与不耗尽内存的情况下处理大文件,这为大文件的处理提供了一个有用的解决办法。
所有这些例子的实现和代码片段都可以在我的github项目上获取到,这是一个基于Eclipse的项目,所以它应该很容易被导入和运行。
以上就是本文关于Java高效读取大文件实例分析的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!