首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 讀取大文件高效方案對比:BufferedReader、Scanner、Commons IO 實戰效能測試

     編輯:Java 相關知識

前言:大文件讀取的常見場景與挑戰

實際開發中頻繁遇到大文本文件讀取需求:FTP 文件落地入庫、日志分析、數據遷移等。文件動輒上百 MB 甚至 GB 級,若一次性 readAllLines() 導致 OOM,必須採用 流式讀取、緩衝、分塊處理。本文對比三種主流方案並實測效能。

測試數據準備

利用 Oracle SQL 生成 100 萬行測試數據(格式:編號|姓名|手機號):

SELECT LEVEL || '|' || '張' || LEVEL || '|' || (13900000000 + LEVEL)
FROM DUAL CONNECT BY LEVEL < 1000000;

測試數據示例

三種方案實現代碼

package com.test.common.util;

import java.io.*;
import java.util.Scanner;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;

public class HandleTextFile {

    // 方案一:Commons IO LineIterator(推薦大文件)
    public static void readTxtFileByFileUtils(String fileName) {
        File file = new File(fileName);
        try {
            LineIterator lineIterator = FileUtils.lineIterator(file, "UTF-8");
            while (lineIterator.hasNext()) {
                String line = lineIterator.nextLine();
                System.out.println(line); // 實際業務替換為解析入庫邏輯
            }
            lineIterator.close(); // 必須關閉釋放資源
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 方案二:Scanner(簡單但大文件效能一般)
    public static void readTxtByScanner(String fileName) {
        FileInputStream fis = null;
        Scanner scanner = null;
        try {
            fis = new FileInputStream(fileName);
            scanner = new Scanner(fis, "UTF-8");
            while (scanner.hasNext()) {
                String line = scanner.nextLine();
                System.out.println(line);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) try { fis.close(); } catch (IOException e) { e.printStackTrace(); }
            if (scanner != null) scanner.close();
        }
    }

    // 方案三:BufferedReader + 大緩衝區(原生高效)
    public static void readTxtByStringBuffer(String fileName) throws IOException {
        File file = new File(fileName);
        BufferedReader reader = null;
        try {
            // 10MB 緩衝區,大幅減少系統調用次數
            reader = new BufferedReader(new FileReader(file), 10 * 1024 * 1024);
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) reader.close();
        }
    }

    public static void main(String[] args) {
        try {
            HandleTextFile.readTxtByStringBuffer("D:\\test\\customer_info.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

方案對比與選型建議

方案優點缺點適用場景
BufferedReader (大緩衝區) 原生 API,無第三方依賴;緩衝區可調優化 IO;內存佔用極低(逐行處理) 代碼相對繁瑣,需手動關閉資源 首選方案:超大文件、高效能要求、無依賴限制
Commons IO LineIterator API 簡潔,自動處理編碼、關閉;支持逐行迭代 引入依賴;內部仍基於 BufferedReader 追求代碼簡潔、項目已引入 Commons IO
Scanner 功能豐富(正則分隔、類型轉換);API 友好 大文件效能最差;緩衝區不可調;內部同步開銷大 小文件、複雜解析邏輯(如正則分割、直接 nextInt())

核心優化原則

  1. 務必使用緩衝:無論哪種方案,底層必須有 BufferedReader 或等效緩衝機制;
  2. 調大緩衝區:大文件場景建議 8MB-16MB(代碼中 10MB),大幅減少系統調用與上下文切換;
  3. 逐行處理,勿全量加載:循環 readLine(),業務邏輯在循環內完成(解析、入庫、過濾),避免列表累積導致 OOM;
  4. 編碼顯式指定:UTF-8 或業務約定編碼,防止亂碼;
  5. 資源確實關閉:使用 try-with-resources (Java 7+) 或 finally 塊確保流關閉。

進階擴展

  • 並行處理:文件可分片(按行號/位移),多線程並行讀取解析,配合線程池與批量入庫;
  • 異步非阻塞 IO (NIO):極高併發場景可考慮 FileChannel + ByteBuffer,但代碼複雜度大幅上升;
  • 內存映射文件:MappedByteBuffer 將文件映射到內存,適合隨機訪問、多進程共享,但受限於虛擬內存大小。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved