關於逐行讀取大文件 , 找了一些方法進行比較驗證, 並下載了一個比較大一點的日誌文件用來測試。
- 使用BufferedReader讀取文件(InputStreamReader、FileReader)
- 使用 Scanner函數來讀取文件
- Apache的commons-io包讀取文件
使用BufferedReader讀取文件
使用java.io.BufferedReader、InputStreamReader函數逐行讀取,代碼如下:
File file = new File(filePath);
BufferedReader buf = null;
try{
buf = new BufferedReader(new InputStreamReader(
new FileInputStream(file), "UTF-8"));
String temp = null ;
while ((temp = buf.readLine()) != null ){
// System.out.println(temp);
}
}catch(Exception e){
e.getStackTrace();
}finally{
if(buf != null){
try{
buf.close();
} catch (IOException e) {
e.getStackTrace();
}
}
}
運行後,查看日誌解析文件消耗時間:4434ms
使用java.io.BufferedReader、FileReader函數讀取,代碼如下:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class FileUtil
{
public static String readFile(File file)
{
try
{
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
Throwable localThrowable3 = null;
try {
StringBuffer sb = new StringBuffer();
String s;
while ((s = bufferedReader.readLine()) != null) {
sb.append(s);
}
String str1 = sb.toString();
return str1;
}
catch (Throwable localThrowable1)
{
localThrowable3 = localThrowable1; throw localThrowable1;
}
finally
{
if (bufferedReader != null)
if (localThrowable3 != null)
try { bufferedReader.close();
} catch (Throwable localThrowable2) {
localThrowable3.addSuppressed(localThrowable2);
}
else bufferedReader.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
運行後,查看日誌解析文件消耗時間:5103ms
使用 Scanner函數來讀取文件
使用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);
}
if (sc.ioException() != null) {
throw sc.ioException();
}
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (sc != null) {
sc.close();
}
}
這種方案將會遍歷文件中的所有行——允許對每一行進行處理,而不保持對它的引用。總之沒有把它們存放在內存中。
運行後,查看日誌解析文件消耗時間:9162ms
使用Common-IO提供的函數
使用Apache的commons-io包逐行讀取,代碼如下:
LineIterator it=null;
try {
it = FileUtils.lineIterator(new File(path), "UTF-8");
while (it.hasNext()) {
String line = it.nextLine();
//System.out.println(line);
}
}catch (IOException e) {
e.printStackTrace();
} finally {
LineIterator.closeQuietly(it);
}
由於整個文件不是全部存放在內存中。
運行後,查看日誌解析文件消耗時間:5103ms
在內存中讀取
讀取文件行的標準方式是在內存中讀取,Guava 和Apache Commons IO都提供瞭如下所示快速讀取文件行的方法:
Files.readLines(new File(path), Charsets.UTF_8);
FileUtils.readLines(new File(path));
這種方法帶來的問題是文件的所有行都被存放在內存中,當文件足夠大時很快就會導致程序拋出OutOfMemoryError 異常。
例如:讀取一個大約1G的文件:
try {
Files.readLines(new File(filePath), Charset.defaultCharset());
} catch (IOException e) {
e.printStackTrace();
}
這種方式開始時只佔用很少的內存。
運行後,查看日誌解析文件消耗時間:5727ms
從上述幾種解析文件消耗時間長短來看,其中BufferedReader 和common-io使用的時間最短,消耗的內存最小。其實FileUtils.lineIterator方法的實現,也是基於BufferedReader 的。所以大文件讀取推薦使用BufferedReader。