1、概述

本教程将演示如何用Java高效地读取大文件。这篇文章是Baeldunghttp://www.baeldung.com/“Java——回归基础”系列教程的一部分。

2、在内存中读取

读取文件行的标准方式是在内存中读取,Guava 和Apache Commons IO都提供了如下所示快速读取文件行的方法:

Files.readLines(new File(path), Charsets.UTF_8);

FileUtils.readLines(new File(path));

这种方法带来的问题是文件的所有行都被存放在内存中,当文件足够大时很快就会导致程序抛出OutOfMemoryError 异常。

例如:读取一个大约1G的文件:

@Test
public void givenUsingGuava_whenIteratingAFile_thenWorks() throws IOException {
String path = ...
Files.readLines(new File(path), Charsets.UTF_8);
}

这种方式开始时只占用很少的内存:(大约消耗了0Mb内存

[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的内存——原因很简单:现在文件的所有行都被存储在内存中。

把文件所有的内容都放在内存中很快会耗尽可用内存——不论实际可用内存有多大,这点是显而易见的。

此外,我们通常不需要把文件的所有行一次性地放入内存中——相反,我们只需要遍历文件的每一行,然后做相应的处理,处理完之后把它扔掉。所以,这正是我们将要做的——通过行迭代,而不是把所有行都放在内存中。

3、文件流

现在让我们看下这种解决方案——我们将使用java.util.Scanner类扫描文件的内容,一行一行连续地读取:

FileInputStream inputStream = null;
Scanner sc = null;
try {
inputStream = new FileInputStream(path);
sc = new Scanner(inputStream, "UTF-8");
while (sc.hasNextLine()) {
String line = sc.nextLine();
// System.out.println(line);
}
// note that Scanner suppresses exceptions
if (sc.ioException() != null) {
throw sc.ioException();
}
} finally {
if (inputStream != null) {
inputStream.close();
}
if (sc != null) {
sc.close();
}
}

这种方案将会遍历文件中的所有行——允许对每一行进行处理,而不保持对它的引用。总之没有把它们存放在内存中(大约消耗了150MB内存)

[main] INFO  org.baeldung.java.CoreJavaIoUnitTest - Total Memory: 763 Mb
[main] INFO org.baeldung.java.CoreJavaIoUnitTest - Free Memory: 605 Mb

4、Apache Commons IO

同样也可以使用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);
}

由于整个文件不是全部存放在内存中,这也就导致相当保守的内存消耗:(大约消耗了150MB内存)

[main] INFO  o.b.java.CoreJavaIoIntegrationTest - Total Memory: 752 Mb
[main] INFO o.b.java.CoreJavaIoIntegrationTest - Free Memory: 564 Mb

5、结论

这篇短文介绍了如何在不重复读取与不耗尽内存的情况下处理大文件——这为大文件的处理提供了一个有用的解决办法。

所有这些例子的实现和代码片段都可以在我的github项目上获取到——这是一个基于Eclipse的项目,所以它应该很容易被导入和运行。

最新文章

  1. 区间第K大(一)
  2. js数组键入值push和 arr[]i]区别
  3. scrollbar_test
  4. The ServiceClass object does not implement the required method in the following form: OMElement sayHello(OMElement e)
  5. 快速幂取模 POJ 3761 bubble sort
  6. Spring4整合Hibernate4详细示例
  7. Windows下安装Python3.4.2
  8. Windows系统前端常用PS快捷键:
  9. GetStdHandle 函数--获取标准设备的句柄
  10. ubuntu 一些琐碎知识
  11. 什么是JWT(JSON WEB TOKEN)
  12. Django的邮件发送以及云服务器上遇到的问题
  13. 关于Linux与Windows的在服务器的一些区别
  14. 微信小程序获取二维码参数
  15. 深入理解JVM(七)JVM类加载机制
  16. Linux记录-lsof打开文件工具常用操作
  17. python的扩展包requests的高级用法
  18. ZooKeeper学习总结 第二篇:ZooKeeper深入探讨
  19. APP安全测评checklist---Android
  20. tensorRT 构建推理引擎

热门文章

  1. Auto Layout 在iOS屏幕适配中的使用
  2. SimpleDateFormat 相关用法
  3. spring(三)----大概是最简单的面向切面了
  4. ASP.NET Ajax简单的无刷新分页
  5. Android Studio使用OpenCV后,使APP不安装OpenCV Manager即可运行
  6. 【学习笔记】【C语言】三目运算符
  7. ionic项目相关的操作命令
  8. 杭电2034——人见人爱A-B
  9. 引入OO开发报表后的感想
  10. iOS 非ARC基本内存管理系列总结6 -设计微博模型