前言

上周负责的模块中需要逐行读取文件内容, 写完之后对程序执行效率不太满意, 索性上网查了一下 Java 逐行读取文件内容的各种方法, 并且简单地比对了一下执行效率. 在此记录, 希望能够帮到有需要的人.

注意: 本文比对的项目为 逐行读取文本内容, 并不能代表其他方式的文件读取效率优劣!!!

文末有完整代码.

先放结果

1000000 行文本读取结果比对:

BufferedReader 耗时: 49ms

Scanner 耗时: 653ms

Apache Commons IO 耗时: 44ms

InputStreamReader 耗时: 191ms

FileInputStream 耗时: 3171ms

BufferedInputStream 耗时: 70ms

FileUtils 耗时: 46ms

Files 耗时: 99ms

24488656 行文本读取结果比对:

BufferedReader 耗时: 989ms

Scanner 耗时: 11899ms

Apache Commons IO 耗时: 568ms

InputStreamReader 耗时: 3377ms

FileInputStream 耗时: 78903ms

BufferedInputStream 耗时: 1480ms

FileUtils 耗时: 16569ms

Files 耗时: 25162ms

可见, 当文件较小时:

ApacheCommonsIO 流 表现最佳;

FileUtils, BufferedReader 居其二;

BufferedInputStream, Files 随其后;

InputStreamReader, Scanner, FileInputStream 略慢.

当文件较大时, Apache Commons IO 流, BufferedReader 依然出色, Files, FileUtils 速度开始变慢.

简要分析

使用到的工具类包括:

java.io.BufferedReader

java.util.Scanner

org.apache.commons.io.FileUtils

java.io.InputStreamReader

java.io.FileInputStream

java.io.BufferedInputStream

com.google.common.io.Files

其中:

Apache Commons IO 流 和 BufferedReader 使用到了缓冲区, 所以在不消耗大量内存的情况下提高了处理速度;

FileUtils 和 Files 是先把文件内容全部读入内存, 然后在进行操作, 是典型的空间换时间案例. 这种方法可能会大量消耗内存, 建议酌情使用;

其他几个工具类本来就不擅长逐行读取, 效率底下也是情理之中.

建议

在逐行读取文本内容的需求下, 建议使用 Apache Commons IO 流, 或者 BufferedReader, 既不会过多地占用内存, 也保证了优异的处理速度.

参考文献:

[Java]读取文件方法大全 --- lovebread

java读取文件API速度对比 --- fengxingzhe001

Java高效读取大文件 --- Eugen Paraschiv[文] / ImportNew - 进林[译]

附录-源代码:

import com.google.common.io.Files;

import org.apache.commons.io.Charsets;

import org.apache.commons.io.FileUtils;

import org.apache.commons.io.LineIterator;

import java.io.*;

import java.util.List;

import java.util.Random;

import java.util.Scanner;

/**

* @Description: 逐行读取文件性能对比

* @Author: Seven-Steven

* @Date: 19-1-25

**/

public class ReadByLineFromFileTest {

public static void main(String[] args) {

ReadByLineFromFileTest test = new ReadByLineFromFileTest();

String filePath = "./testFile.txt";

File file = new File(filePath);

if (!file.exists()) {

// 随机写入 1000000 行内容

test.writeRandom(filePath, 1000000);

}

long before, after, time;

// 使用 BufferedReader 逐行读取文件

before = System.currentTimeMillis();

test.bufferedReader(filePath);

after = System.currentTimeMillis();

time = after - before;

System.out.println("BufferedReader 耗时: " + time + "ms");

// 使用 Scanner 逐行读取文件

before = System.currentTimeMillis();

test.scanner(filePath);

after = System.currentTimeMillis();

time = after - before;

System.out.println("Scanner 耗时: " + time + "ms");

// 使用 Apache Commons IO 流逐行读取文件

before = System.currentTimeMillis();

test.apacheCommonsIo(filePath);

after = System.currentTimeMillis();

time = after - before;

System.out.println("Apache Commons IO 耗时: " + time + "ms");

// 使用 InputStreamReader 逐字符读取文件

before = System.currentTimeMillis();

test.inputStreamReader(filePath);

after = System.currentTimeMillis();

time = after - before;

System.out.println("InputStreamReader 耗时: " + time + "ms");

// 使用 FileInputStream 逐字符读取文件

before = System.currentTimeMillis();

test.fileInputStream(filePath);

after = System.currentTimeMillis();

time = after - before;

System.out.println("FileInputStream 耗时: " + time + "ms");

// 使用 BufferedInputStream 逐字符读取文件

before = System.currentTimeMillis();

test.bufferedInputStream(filePath);

after = System.currentTimeMillis();

time = after - before;

System.out.println("BufferedInputStream 耗时: " + time + "ms");

// 使用 FileUtils 一次性读取文件所有行

before = System.currentTimeMillis();

test.fileUtils(filePath);

after = System.currentTimeMillis();

time = after - before;

System.out.println("FileUtils 耗时: " + time + "ms");

// 使用 Files 一次性读取文件所有行

before = System.currentTimeMillis();

test.files(filePath);

after = System.currentTimeMillis();

time = after - before;

System.out.println("Files 耗时: " + time + "ms");

}

/**

* @Description: 使用 Apache Commons IO 流逐行读取文件

* Maven 依赖:

*

*

* commons-io

* commons-io

* 2.6

*

* @Param: [filePath] 文件路径

* @Author: Seven-Steven

* @Date: 19-1-24

**/

public void apacheCommonsIo(String filePath) {

File file = new File(filePath);

if (!file.exists()) {

return;

}

try {

LineIterator iterator = FileUtils.lineIterator(file, "UTf-8");

while (iterator.hasNext()) {

String line = iterator.nextLine();

// TODO

// System.out.println(line);

}

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* @Description: 使用 Scanner 类逐行读取

* @Param: [filePath] 文件路径

* @Author: Seven-Steven

* @Date: 19-1-24

**/

public void scanner(String filePath) {

File file = new File(filePath);

if (!file.exists()) {

return;

}

FileInputStream fileInputStream = null;

Scanner scanner = null;

try {

fileInputStream = new FileInputStream(file);

scanner = new Scanner(fileInputStream, "UTF-8");

while (scanner.hasNextLine()) {

// TODO things

String line = scanner.nextLine();

// System.out.println(line);

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} finally {

if (fileInputStream != null) {

try {

fileInputStream.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if (scanner != null) {

scanner.close();

}

}

}

/**

* @Description: 使用 Files 一次性读取所有行

* Maven 依赖:

*

*

* com.google.guava

* guava

* r05

*

* @Param: [filePath] 文件路径

* @Author: Seven-Steven

* @Date: 19-1-24

**/

public void files(String filePath) {

File file = new File(filePath);

if (!file.exists()) {

return;

}

try {

List fileLines = Files.readLines(file, Charsets.toCharset("UTF-8"));

for (String str : fileLines) {

// TODO things

// System.out.println(str);

}

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* @Description: 使用 FileUtils 一次性将文件所有行读入内存

* Maven 依赖:

*

*

* commons-io

* commons-io

* 2.6

*

* @Param: [filePath] 文件路径

* @Author: Seven-Steven

* @Date: 19-1-24

**/

public void fileUtils(String filePath) {

File file = new File(filePath);

if (!file.exists()) {

return;

}

try {

List fileLines = FileUtils.readLines(file, Charsets.UTF_8);

for (String str : fileLines) {

// TODO

// System.out.println(str);

}

} catch (IOException e) {

e.printStackTrace();

}

}

public void bufferedInputStream(String filePath) {

File file = new File(filePath);

if (!file.exists()) {

return;

}

FileInputStream fileInputStream = null;

BufferedInputStream bufferedInputStream = null;

try {

fileInputStream = new FileInputStream(file);

bufferedInputStream = new BufferedInputStream(fileInputStream);

int temp;

char character;

String line = "";

while ((temp = bufferedInputStream.read()) != -1) {

character = (char) temp;

if (character != '\n') {

line += character;

} else {

// TODO

// System.out.println(line);

line = "";

}

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} finally {

if (fileInputStream != null) {

try {

fileInputStream.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if (bufferedInputStream != null) {

try {

bufferedInputStream.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

/**

* @Description: 使用 FileInputStream 逐字符读取文件

* @Param: [filePath] 文件路径

* @Author: Seven-Steven

* @Date: 19-1-23

**/

public void fileInputStream(String filePath) {

File file = new File(filePath);

if (!file.exists()) {

return;

}

FileInputStream fileInputStream = null;

try {

fileInputStream = new FileInputStream(file);

int temp;

char character;

String line = "";

while ((temp = fileInputStream.read()) != -1) {

character = (char) temp;

if (character != '\n') {

line += character;

} else {

// TODO

// System.out.println(line);

line = "";

}

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} finally {

if (fileInputStream != null) {

try {

fileInputStream.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

/**

* @Description: 使用 InputStreamReader 逐行读取文件

* @Param: [filePath] 文件路径

* @Author: Seven-Steven

* @Date: 19-1-23

**/

public void inputStreamReader(String filePath) {

File file = new File(filePath);

if (!file.exists()) {

return;

}

FileInputStream fileInputStream = null;

InputStreamReader inputStreamReader = null;

try {

fileInputStream = new FileInputStream(file);

inputStreamReader = new InputStreamReader(fileInputStream);

int temp;

char character;

String line = "";

while ((temp = inputStreamReader.read()) != -1) {

character = (char) temp;

if (character != '\n') {

line += character;

} else {

// TODO

// System.out.println(line);

line = "";

}

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} finally {

if (fileInputStream != null) {

try {

fileInputStream.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if (inputStreamReader != null) {

try {

inputStreamReader.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

/**

* @Description: 使用 BufferedReader 逐行读取文件内容

* @Param: [filePath] 文件路径

* @Author: Seven-Steven

* @Date: 19-1-23

**/

public void bufferedReader(String filePath) {

File file = new File(filePath);

if (!file.exists()) {

return;

}

FileReader fileReader = null;

BufferedReader bufferedReader = null;

try {

fileReader = new FileReader(file);

bufferedReader = new BufferedReader(fileReader);

String line = "";

while ((line = bufferedReader.readLine()) != null) {

// TODO things

// System.out.println(line);

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} finally {

if (fileReader != null) {

try {

fileReader.close();

} catch (IOException e) {

e.printStackTrace();

}

}

if (bufferedReader != null) {

try {

bufferedReader.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

/**

* @Description: 随机往文件中写入 totalLines 行内容

* @Param: [filePath, totalLines] 文件路径, 内容行数

* @Author: Seven-Steven

* @Date: 19-1-23

**/

public void writeRandom(String filePath, int totalLines) {

RandomAccessFile file = null;

Random random = new Random();

try {

file = new RandomAccessFile(filePath, "rw");

long length = file.length();

for (int i = 0; i < totalLines; i++) {

file.seek(length);

int number = random.nextInt(1000000);

String line = number + "\n";

file.writeBytes(line);

length += line.length();

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} finally {

if (file != null) {

try {

file.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

}

java 读取文件 效率_Java 逐行读取文本文件的几种方式以及效率对比相关推荐

  1. java 读文件 二进制_JAVA中读取文件(二进制,字符)内容的几种方法总结

    JAVA中读取文件内容的方法有很多,比如按字节读取文件内容,按字符读取文件内容,按行读取文件内容,随机读取文件内容等方法,本文就以上方法的具体实现给出代码,需要的可以直接复制使用 public cla ...

  2. java 读取文件内容_Java如何读取txt文件的内容?

    这个并不困难,大概的步骤是这样的: TXT是一个文本文件,一般采用流的方式读取: java提供了一个FileInputStream,我们可以直接以文件路径构造这个流,也可以以文件对象构造他,如:Fil ...

  3. java 读取文件 二进制_JAVA中读取文件(二进制,字符)内容的几种方法总结

    public class ReadFromFile { /** * 以字节为单位读取文件,常用于读二进制文件,如图片.声音.影像等文件. */ public static void readFileB ...

  4. linux shell读取文件,Linux shell逐行读取文件的方法

    方法1:while循环中执行效率最高,最常用的方法. function while_read_LINE_bottm(){ While read LINE do echo $LINE done } 注释 ...

  5. java 数组 源码_Java数组转List的三种方式及对比

    来源:https://s.yam.com/6wu6n 前言: 本文介绍Java中数组转为List三种情况的优劣对比,以及应用场景的对比,以及程序员常犯的类型转换错误原因解析. 一.最常见方式(未必最佳 ...

  6. java 连接池配置_java数据库连接池配置的几种方式

    关于java数据库连接池配置的几种方式 今天遇到了关于数据源连接池配置的问题,发现有很多种方式可以配置,现总结如下,(已Mysql数据库为例) 一,Tomcat配置数据源: 方式一:在WebRoot下 ...

  7. java类初始数组_java中数组初始化的三种方式是什么

    java中数组初始化的三种方式是:1.静态初始化,如[int a[] = {2, 0, 1, 9, 2020}]:2.动态初始化,如[int[] c = new int[4]]:3.默认初始化,如[i ...

  8. java调用restful接口_Java调用RESTful接口的几种方式

    前端一般通过Ajax来调用,后端调用的方式还是挺多的,比如HttpURLConnection,HttpClient,Spring的RestTemplate 服务端代码如下: 服务端接口请求的URL:h ...

  9. java properties文件 安全_java 数据库读取工具类(读取config.properties配置文件)[包含线程安全] | 学步园...

    java 数据库读取工具类(读取config.properties配置文件)[包含线程安全] 数据库读取工具类 package com.db; import java.sql.Connection; ...

最新文章

  1. 怎么新建android.mk,Android NDK简单编写HelloWorld过程笔记(详细)
  2. 让VisualStudio的StartPage关联自己的博客
  3. 上顿号符号_标点符号常见错误,读后涨知识了
  4. 在Python中导入自己写的类,被划红线,但不影响执行
  5. 什么是区块链预言机(BlockChain Oracle)
  6. 前端学习(1185):数据响应式
  7. script地下状态栏效果
  8. 挑战练习题2.3动态规划 poj3046 Ant Counting dp
  9. 【Golang】如何不反序列化为前提的情况下,修改ProtoBuffer某个Tag的值
  10. chrome文字转语音(tts)
  11. LeetCode | 面试题04. 二维数组中的查找【剑指Offer】【Python】
  12. c语言数字大小排序的理解,教孩子数字比大小,排序很重要
  13. 证明左右特征向量正交
  14. 解决方案(二)— 将 http://apache.org/xml/features/disallow-doctype-decl 设置为“true”时, 不允许使用 DOCTYPE
  15. 1命名规则 sentinel_哨兵-1A数据命名规则
  16. 搭建日志服务器 rsyslog
  17. 前端数据库indexedDB入门
  18. leetcode|一道算法题错失谷歌offer
  19. H2 database文档学习
  20. Moveit实际的机械臂控制(4)修改机械臂配置文件实现真实控制

热门文章

  1. 【蓝桥杯单片机组第十届决赛】— 客观试题
  2. 微信小程序的自学之路一按钮篇
  3. Django 4.x Test 单元测试使用示例和配置方法
  4. CSS过渡-Transitions
  5. codeforces 915E - Physical Education Lessons 动态开点线段树
  6. 如何设置文件夹安全权限
  7. ARX测试_绘制道路横断面
  8. 下载量Top 1的内容社交软件 —— TikTok产品分析竞品分析
  9. 操作系统五大功能之作业管理
  10. Linux背景知识(1)RedHat和Centos