1、概述

本教程将演示如何用Java高效地读取大文件。这篇文章是Baeldung (http://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的项目,所以它应该很容易被导入和运行。

Java读取大文件的高效率实现的更多相关文章

  1. java读取 500M 以上文件,java读取大文件

    java 读取txt,java读取大文件 设置缓存大小BUFFER_SIZE ,Config.tempdatafile是文件地址 来源博客http://yijianfengvip.blog.163.c ...

  2. java 读取txt,java读取大文件

    java 读取txt,java读取大文件 package com.bbcmart.util; import java.io.File;import java.io.RandomAccessFile;i ...

  3. java读取大文件

    1  多线程 2  java内存映射读取大文件

  4. Java 读取大文件方法

    需求:实际开发中读取文本文件的需求还是很多,如读取两个系统之间FTP发送文件,读取后保存到数据库中或日志文件的数据库中保存等. 为了测试首先利用数据库SQL生成大数据文件. 规则是 编号|姓名|手机号 ...

  5. java读取大文件 超大文件的几种方法

    java 读取一个巨大的文本文件既能保证内存不溢出又能保证性能       import java.io.BufferedReader; import java.io.File; import jav ...

  6. java读取大文件内容到Elasticsearch分析(手把手教你java处理超大csv文件)

    现在需要快算分析一个2g的csv文件: 基于掌握的知识,使用java按行读取文件,批量导入数据到es, 然后利用es强大的聚合能力分析数据,2个小时搞定! package com.example.de ...

  7. 解决java读取大文件内存溢出问题

    1. 传统方式:在内存中读取文件内容 读取文件行的标准方式是在内存中读取,Guava 和Apache Commons IO都提供了如下所示快速读取文件行的方法: Files.readLines(new ...

  8. Java多线程读取大文件

    前言 今天是五一假期第一天,按理应该是快乐玩耍的日子,但是作为一个北漂到京师的开发人员,实在难想出去那玩耍.好玩的地方比较远,近处又感觉没意思.于是乎,闲着写篇文章,总结下昨天写的程序吧. 昨天下午朋 ...

  9. java 分次读取大文件的三种方法

    1. java 读取大文件的困难 java 读取文件的一般操作是将文件数据全部读取到内存中,然后再对数据进行操作.例如 Path path = Paths.get("file path&qu ...

随机推荐

  1. 第二周:Scrum Meeting

    一.站立会议 顾名思义,站立会议即是在敏捷开发的冲刺阶段,为了更好地平衡团队成员的“交流”和“集中注意力”之间的矛盾.通过每日例会,即团队成员通过面对面的交流,并且其中大多数团队成员站着对会议进行讨论 ...

  2. 【转】mysql force Index 强制索引

    其他强制操作,优先操作如下: mysql常用的hint 对于经常使用oracle的朋友可能知道,oracle的hint功能种类很多,对于优化sql语句提供了很多方法.同样,在mysql里,也有类似的h ...

  3. zepto中$.proxy()的到底有多强大?

    好吧,其实是标题党了,哈哈,只是想总结一下工作中遇到$.proxy()的用法而已. 一.语法: $.proxy()有两种使用语法 1)$.proxy(fn,context),fn是一个函数,conte ...

  4. HDU 4767——Bell

    昨天比赛被虐的这个题目. 今天听斌牛讲过他的思路后就A掉了. 题目的意思是要你求出bell数的第n项对95041567取模. 首先,95041567=31*37*41*43*47: 然后取模就是先分别 ...

  5. CSUOJ1329——一行盒子_湖南省第九届大学生计算机程序设计竞赛

    题目是中文的我就不是说明了,比赛的时候看过题目后队友说是splay来做,细想来省赛不会出这么坑的题目吧. 于是比赛还有一个小时左右把该做的都做完了以后,我们队三个人都来思考这个题目了.不过还好很快我们 ...

  6. 【bzoj3573】[HNOI2014]米特运输 树形dp

    题目描述 米特是D星球上一种非常神秘的物质,蕴含着巨大的能量.在以米特为主要能源的D星上,这种米特能源的运输和储存一直是一个大问题.D星上有N个城市,我们将其顺序编号为1到N,1号城市为首都.这N个城 ...

  7. 【HLSDK系列】服务端实体 edict_t 和 控制类

    我们来了解一下引擎是怎么管理实体的吧!我们这里就说说服务端的实体(edict_t) 服务端用 edict_t 这个结构体来保存一个实体,可以说一个 edict_t 就是一个 服务端实体,下文简称实体. ...

  8. UIScrollView 在手指点击的坐标处放大

    写了一个extension,如下: extension UIScrollView{ ///在ScrollView上的某个点放大 func zoomWithPoint(var zoomPoint:CGP ...

  9. Jsp遍历后台传过来的List

    1:使用jstl标签 (可以和自定义标签配合使用) 首先引用jstl标签 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" ...

  10. 【BZOJ2653】Middle(主席树)

    [BZOJ2653]Middle(主席树) 题面 BZOJ 洛谷 Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你 ...