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

PHP 高效讀取大型 CSV 檔案封裝類 CsvReader 實作

     編輯:PHP 相關知識

處理大型 CSV 檔案(數百 MB 甚至 GB 級別)時,傳統 fopen + fgetcsv 逐行讀取容易導致超時或記憶體耗盡。本文介紹基於 SplFileObject 的高效解決方案,並封裝為可複用的 CsvReader 類。

核心技術難點與解決方案

1. 快速獲取大檔案總行數

方案一:file() 載入全檔 → 記憶體爆炸 ❌

方案二:fgets() 逐行計數 → 速度慢、易超時 ❌

方案三(推薦):SplFileObject::seek() 定位檔案末尾 + key() 獲取行號 ✅

$csv_file = 'path/bigfile.csv';
$spl_object = new SplFileObject($csv_file, 'rb');
$spl_object->seek(filesize($csv_file));
echo $spl_object->key();  // 即時獲取總行數

2. 快速隨機讀取指定區間資料

$csv_file = 'path/bigfile.csv';
$start = 100000;  // 從第 100,000 行開始
$num = 100;       // 讀取 100 行

$spl_object = new SplFileObject($csv_file, 'rb');
$spl_object->seek($start);
$data = array();
while ($num-- && !$spl_object->eof()) {
    $data[] = $spl_object->fgetcsv();
    $spl_object->next();
}
print_r($data);

CsvReader 完整封裝類

<?php
class CsvReader {
    private $csv_file;
    private $spl_object = null;
    private $error;

    public function __construct($csv_file = '') {
        if ($csv_file && file_exists($csv_file)) {
            $this->csv_file = $csv_file;
        }
    }

    public function set_csv_file($csv_file) {
        if (!$csv_file || !file_exists($csv_file)) {
            $this->error = 'File invalid';
            return false;
        }
        $this->csv_file = $csv_file;
        $this->spl_object = null;
    }

    public function get_csv_file() {
        return $this->csv_file;
    }

    private function _file_valid($file = '') {
        $file = $file ? $file : $this->csv_file;
        if (!$file || !file_exists($file)) return false;
        if (!is_readable($file)) return false;
        return true;
    }

    private function _open_file() {
        if (!$this->_file_valid()) {
            $this->error = 'File invalid';
            return false;
        }
        if ($this->spl_object == null) {
            $this->spl_object = new SplFileObject($this->csv_file, 'rb');
        }
        return true;
    }

    /**
     * 獲取指定區間資料
     * @param int $length 讀取行數(預設讀到檔案結尾)
     * @param int $start 起始行號(從 1 開始)
     * @return array|false
     */
    public function get_data($length = 0, $start = 0) {
        if (!$this->_open_file()) return false;
        $length = $length ? $length : $this->get_lines();
        $start = $start - 1;
        $start = ($start < 0) ? 0 : $start;
        
        $data = array();
        $this->spl_object->seek($start);
        while ($length-- && !$this->spl_object->eof()) {
            $data[] = $this->spl_object->fgetcsv();
            $this->spl_object->next();
        }
        return $data;
    }

    /**
     * 獲取檔案總行數
     * @return int|false
     */
    public function get_lines() {
        if (!$this->_open_file()) return false;
        $this->spl_object->seek(filesize($this->csv_file));
        return $this->spl_object->key();
    }

    public function get_error() {
        return $this->error;
    }
}

使用範例

<?php
include('CsvReader.class.php');

$csv_file = 'path/bigfile.csv';
$csvreader = new CsvReader($csv_file);

// 獲取總行數
$line_number = $csvreader->get_lines();

// 讀取前 10 行
$data = $csvreader->get_data(10);

echo $line_number, "\n";
print_r($data);

擴展應用

此類不僅限於 CSV,只要將 fgetcsv() 改為 current() 即可處理任意大型文字檔案(如日誌、JSON Lines 等)。

效能優勢總結

  • 記憶體友善:不載入整個檔案,適合 GB 級大檔
  • 隨機存取:seek() 可直接跳轉到任意行,無需循序讀取
  • 原生效能:SplFileObject 為 C 底層實現,比純 PHP 循環快數倍
  • 介面統一:封裝後介面簡潔,易於整合至現有專案
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved