PHP大文件讀取操做

簡單的文件讀取,通常咱們會使用 file_get_contents() 這類方式來直接獲取文件的內容。不過這種函數有個嚴重的問題是它會把文件一次性地加載到內存中,也就是說,它會受到內存的限制。所以,加載大文件的時候是絕對不能使用這種方式的。咱們仍是先看看這種方式加載的例子。php

// 普通的文件讀取 一個2.4G的SQL導出文件
$fileName= './2020-02-23.sql';

// file_get_contents
$fileInfo = file_get_contents($fileName);
// Fatal error: Allowed memory size of 134217728 bytes exhausted

// file
$fileInfo = file($fileName);
// Fatal error: Allowed memory size of 134217728 bytes exhausted

// fopen + fread
$fileHandle = fopen($fileName, 'r');
$fileInfo = fread($fileHandle, filesize($fileName));
// Fatal error: Allowed memory size of 134217728 bytes exhausted

上述三種形式的文件加載讀取方式都是不能加載這麼大的文件的,固然,你也能夠修改 php.ini 中的相關配置讓他們可以加載成功,但咱們並不推薦這樣使用,畢竟內存資源相比硬盤資源仍是要寶貴的多。mysql

如下的方式是能夠直接讀取這種大文件的:git

// readfile 只能直接輸出
echo readfile($fileName);

// fopen + fgetc 若是單
$fileHandle = fopen($fileName, 'r');
// 輸出單字符直到 end-of-file
while(!feof($fileHandle)) {
    echo fgetc($fileHandle);
}
fclose($fileHandle);

// SplFileObject
$fileObject = new SplFileObject($fileName, 'r');
while(!$fileObject->eof()){
    echo $fileObject->fgetc();
}

第一個 readfile() ,讀取文件後就直接打印了,不能進行其餘操做,適用於直接顯示大文件內容時使用。github

第二個 fopen() 配合 fgetc() 或 fgets() 是讀取這種大文件的標配。fopen() 獲取文件句柄,fgetc() 按字符讀取,fgets() 按行讀取。像這個 mysqldump 出來的文件,一行也可能很是的大,因此咱們就只能直接按字符讀取。sql

第三個是SPL擴展庫爲咱們提供的面向對象式的 fopen() 操做,建議新的開發中若是有讀取大文件的需求最好使用這種形式的寫法,畢竟SPL函數庫已是PHP的標準函數庫了,並且面向對象的操做形式也更加的主流。編程

上面三種讀取方式都有一個要注意的點是,咱們將大文件讀取後不該該再保存到變量中,應該直接打印顯示、入庫或者寫到其餘文件中。由於直接讀取到一個變量中就和前面的直接讀取到內存的方式同樣了,那還不如直接去修改下 php.ini 的配置而後使用最上方的方式直接讀取到內存方便。仍是那句話,內存留給真正須要它的地方,這種大文件,最好仍是進行硬盤的IO操做。函數

測試代碼:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202003/source/PHP%E5%A4%A7%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%93%8D%E4%BD%9C.php測試

參考文檔:code

《PHP7編程實戰》

各自媒體平臺都可搜索【硬核項目經理】對象

相關文章
相關標籤/搜索