Java 關於讀取大文件的幾種基本用法

關於逐行讀取大文件 , 找了一些方法進行比較驗證, 並下載了一個比較大一點的日誌文件用來測試。

  • 使用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。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章