Java 按行处理大文件的方法 [单线程]

这篇文章介绍的是Java中处理大文件的一种方法,如有疑问欢迎各位大神垂询,我们相互帮助、共同学习。

一、问题的提出

你是否在Java中遇到过这种问题,将一个大文件读取到内存中,然而内存放不下,JVM报出如下错误:

  • 代码
public static void main(String[] args) throws IOException {
		File file = new File("C:\\Users\\Mr-Leaf\\Desktop\\test2.csv") ;
		//这里直接将文件按行读入内存
		List<String> lines = Lists.newArrayList() ;
		BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8"));
		String line = null ;
		while( (line = reader.readLine()) != null) {
			lines.add(line) ;
		}
		System.out.println("读取文件成功:" + lines.size());
		reader.close();
	}
  • 结果
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOfRange(Unknown Source)
	at java.lang.String.<init>(Unknown Source)
	at java.io.BufferedReader.readLine(Unknown Source)
	at java.io.BufferedReader.readLine(Unknown Source)
	at tests.cn.com.taiji.etl.manager.comm.client.file.TestBigFile.main(TestBigFile.java:44)

显然,我读取的文件太大,我的8G内存放不下了。

二、解决方法

既然一次性加载到内存中的方法行不通,那么考虑将文件的一部分加载到内存中去,代码如下:

  • 代码
public static void main(String[] args) throws IOException {
		File file = new File("C:\\Users\\Mr-Chen\\Desktop\\test2.csv") ;
		List<String> lines = Lists.newArrayList() ;
		BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8"));
		String line = null ;
		while( (line = reader.readLine()) != null) {
			lines.add(line) ;
			//读取前一百万行
			if(lines.size() >= 1000000) {
				break ;
			}
		}
		System.out.println("读取文件成功:" + lines.size());
		reader.close();
	}
  • 运行结果
读取文件成功:1000000

三、工具方法

接着这个思路,我将这个读取部分文件的方法抽取成一个工具方法,如有需要可直接考走用,代码如下:

  • 代码
	/**
	 * 

功能:

* @param file 要读取的文件 * @param encoding 编码格式 * @param startLine 开始读取的行数 * @param size 要读取的量 * @return * @throws IOException */
public static List<String> copyToLines(File file, String encoding, int startLine, int size) throws IOException { List<String> lines = new ArrayList<String>(); BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), encoding)); try { String line = null; int lineNum = 0; if (startLine < 1) startLine = 1; while ((line = reader.readLine()) != null) { lineNum++; if (startLine > 0 && lineNum < startLine) continue; if (size > 0 && (lineNum - startLine) >= size) break; lines.add(line); } } finally { if (reader != null) reader.close(); } return lines; }

四、存在的问题

  1. 由于是逐行遍历,所以寻道的时间比较久,比如读取1-1000000,和5000000-6000000行的效率相差的特别大。(尽量每次多读取一些数据)
  2. 由于是单线程处理,效率也不是很高。(下一篇我会提供一个多线程的解决方案,敬请期待)

你可能感兴趣的:(java基础)