PHP 大檔案的讀取和寫入問題

來源:互聯網
上載者:User
在通常的學習和開發中,因為我們很少會接觸到大量資料的讀取和寫入,所以當突然有了這種需求的時候,我們可

能仍然會按照一些比較快捷的方法,像file_get_contents,fread等方法來讀取檔案,不過這樣以來如果讀取的檔案太

大,就會產生問題,在實現大檔案讀取和寫入的時候尋找了網上的一些資料,不過有些例子給的不是很符合我的需

求,所以我就結合網上已有的例子,再寫一篇總結性的部落格吧。

那麼究竟會產生什麼問題呢,這就要說一些PHP的底層實現數,file_get_contents和fread來說一下,首先說一下

PHP中檔案讀取的函數,file_get_contents和fread,這兩個函數其實原理是相同的,都是讀取內容到系統的記憶體中,

不過如果只是想將一個檔案的內容讀入到一個字串中,請使用file_get_contents(),它的效能比 fread() 好得多。

在讀取不是很大的檔案還是沒有問題的,不過當讀取大檔案的時候(例如2GB的日誌),如果你機器的記憶體只有4G,

如果你將整個檔案全部讀取然後存入字串中,就可能會導致系統的記憶體爆掉造成卡死,因為還有一部分記憶體要用於

維持系統的運行和其他進程的運行,既然會這樣,我們就需要一些其他辦法來避免一次性讀取太多的內容,通過這種

辦法來實現大檔案的讀取。


PHP檔案讀取:

下面這個是網上讀取大檔案的一個例子,來說明上面記憶體會爆掉的現象。。


_________________________________無敵分割線_______________________________________



需求如下: 現有一個1G左右的記錄檔,大約有500多萬行, 用php返回最後幾行的內容。

實現方法:

1. 直接採用file函數來操作

註:由於 file函數是一次性將所有內容讀入記憶體,而php為了防止一些寫的比較糟糕的程式佔用太多的記憶體而導致系統記憶體不足,使伺服器出現宕機,所以預設情況下限制只能最大使用記憶體16M,這是通過php.ini裡的memory_limit = 16M來進行設定,這個值如果設定-1,則記憶體使用量量不受限制.

下面是一段用file來取出這具檔案最後一行的代碼.
整個代碼執行完成耗時 116.9613 (s).



我機器是2個G的記憶體,當按下F5運行時,系統直接變灰,差不多20分鐘後才恢複過來,可見將這麼大的檔案全部直接讀入記憶體,後果是多少嚴重,所以不在萬不得以,memory_limit這東西不能調得太高,否則只有打電話給機房,讓reset機器了.


_____________________________________無敵分割線_____________________________________


上面的例子雖然是讀取最後幾行的例子,不過由於對檔案的內容進行了遍曆,所以跟讀取整個檔案是一樣的,不過如

果是為了讀取最後幾行的內容,也可以直接用fseek來進行定位讀取部分內容。


下面我們來一起探討下如何對大檔案進行讀取和寫入。


大檔案讀取:

因為要求讀取部分,如果檔案不是特別大,可以通過file_get_contents或fread內建的分割參數來進行分塊來進行讀取(這個地方感覺需要加一個sleep函數,來減少IO的峰值大小,不過不知是否正確,希望大牛指點),還有一種方法,就是通過while迴圈,用fgets來進行逐行的讀取,因為fgetss是通過檔案指標讀取一行,效率是比較高的。


下面附上通過fgets實現的大檔案讀取並對檔案內容進行編碼轉換(UTF-8 -> GBK)的例子,代碼如下:


            $file = fopen($old_file_path,"r");            $result = fopen($temporary_file_path,"a");            $re_sign = 0;             while(!feof($file))            {                $content = fgets($file);                $encode = mb_detect_encoding($content, array('ASCII','UTF-8','GB2312','GBK','BIG5'));                 if ($encode == 'UTF-8') {                    $str = iconv($encode,"GBK//IGNORE", $content);                    $encode = mb_detect_encoding($content, array('ASCII','UTF-8','GB2312','GBK','BIG5'));                     fwrite($result, $str);                     $re_sign = 1;                 } else {                                        fwrite($result, $content);                 }            }            fclose($file);            fclose($result);            if($re_sign == 1){                                rename($old_file_path, $old_file_path . '.bak' );                rename($temporary_file_path, $old_file_path);                            } else {                unlink($temporary_file_path);            }


大檔案寫入:


大檔案的寫入相對大檔案讀取來說產生的代價不是很大,因為檔案寫入是寫入到硬碟中,如果一次性寫入檔案過多,

只會產生卡硬碟的現象,如果從效率上來講一次性直接寫入的耗時和效率最高,所以大檔案的寫入的話建議一次性讀取後直接寫入檔案中。

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.