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. PAT L1 - 056 猜数字

    https://pintia.cn/problem-sets/994805046380707840/problems/994805074646122496 一群人坐在一起,每人猜一个 100 以内的数 ...

  2. GO语言教程(一)Linux( Centos)下Go的安装, 以及HelloWorld

    写在前面: 目前,Go语言已经发布了1.5的版本,已经有不少Go语言相关的书籍和教程了,但是看了一些后,觉得还是应该自己写一套Go语言的教程.给广大学习Go语言的朋友多一种选择.因为,咱写的教程,向来 ...

  3. javascriptDOM编程

    DOM - Document Object Model,它是W3C国际组织的一套Web标准,它定义了访问HTML文档对象的一套属性,方法和事件. <html> <head> & ...

  4. windows安装安卓开发环境Eclipse+SDK+ADT

    准备条件 操作系统:win7 64位 需要的资源:JDK.Eclipse.SDK.ADT 步骤简介: 第一步:下载安装最新版JDK 第二步:下载安装Eclipse 第三步:下载安装SDK 第四步:安装 ...

  5. 【移动端debug-3】部分安卓机型不触发touchend事件的解决方案

    最近在项目中遇到一个奇怪的问题,有一个需求是这样:页面上有一个按钮,滚动页面时让它消失,停止滚动时让它显示. 常规思路: step1.监听touchstart事件,记录Touch对象中pageY初始值 ...

  6. Spring Boot系列教程四:配置文件详解properties

    一.配置随机数,使用随机数 在application.properties文件添加配置信息 #32位随机数 woniu.secret=${random.value} #随机整数 woniu.numbe ...

  7. 51nod1967 路径定向(欧拉回路+结论题)

    看到入度等于出度想到欧拉回路. 我们把边都变成无向边,有一个结论是偶数度的点都可以变成出入度相等的点,而奇数点的不行,感性理解分类讨论一下就知道是对的. 还有一个更好理解的结论是变成无向边后奇数点的个 ...

  8. 洛谷 P1924 poj 1038

    Description: 给你一个n * m的方格纸,有一些格子无法被覆盖,然后用2*3的格子覆盖这个方格纸,问你最多能放多少个格子 神级状压 为了弄清楚这道题翻了无数篇解题报告,最后终于搞明白了 用 ...

  9. 【arc068E】Snuke Line

    Portal -->arc068E (温馨提示:那啥..因为各种奇怪的我也不知道的原因这题的题号在某度上面显示出来是agc007F...然而下面是arc068E的题解qwq给大家带来不便之处真是 ...

  10. python基础----常用模块

    一 time模块(时间模块)★★★★                                                      时间表现形式 在Python中,通常有这三种方式来表示时 ...