如果你想用PHP處理大文件,PHP提供了一些普通的PHP函數(shù),比如file_get_contents()或file()函數(shù),它們在處理超大文件時會存在一定局限性。 其中包括: 1.內(nèi)存限制 上面這些函數(shù)依賴于php.ini中memory_limit的參數(shù)值設(shè)置,可以調(diào)整增加這些值,但這些函數(shù)仍然不適合極大的文件,因為這些函數(shù)會把整個文件內(nèi)容都讀入到內(nèi)存中。 如果文件的尺寸超過memory_limit的設(shè)置,這類文件都不會加載到內(nèi)存中?,F(xiàn)實中,比如我們有一個20G的的文件,想用PHP來處理,該怎么樣處理? 2.不太好的用戶體驗 還有一個限制是生產(chǎn)環(huán)境的速度問題。如果我們把它輸出到數(shù)組中,這樣經(jīng)常會出現(xiàn)在瀏覽器出現(xiàn)很長時間的等待,白頁或者出錯等情況。這樣給用戶的體驗不太好。 對于這種技術(shù)限制,可以使用yield關(guān)鍵字來直接生成一個結(jié)果。 SplFileObject Class 在本文中,我們告訴大家使用PHP標(biāo)準(zhǔn)庫中的SplFileObject類。 我們來演示,創(chuàng)建一個類來處理大文件。 這個類使用文件名做為輸入?yún)?shù)。如下代碼: class BigFile { protected $file;
public function __construct($filename, $mode = 'r') { if (!file_exists($filename)) {
throw new Exception('File not found'); }
$this->file = new SplFileObject($filename, $mode); }
} 接下來,我們定義一個遍歷文件的方法,這個方法將使用fgets()函數(shù)一次讀取文件一行。 我們也可以使用fread()函數(shù)的方法。 讀取文本文件 fgets()適用于解析包含換行符的文本文件,而fread()適用于解析二進制文件。 該函數(shù)用于遍歷文本文件的每一行內(nèi)容。 protected function iterateText() { $count = 0;
while (!$this->file->eof()) {
yield $this->file->fgets();
$count++; } return $count; } 讀取二進制文件 來看另一個讀取二進制的文件: protected function iterateBinary($bytes) { $count = 0;
while (!$this->file->eof()) {
yield $this->file->fread($bytes);
$count++; } } 直接讀取 現(xiàn)在我們將定義一個采用迭代的類型,返回NoRewindIterator實例的方法。 我們使用NoRewindIterator強制單向讀取。 public function iterate($type = 'Text', $bytes = NULL) { if ($type == 'Text') {
return new NoRewindIterator($this->iterateText());
} else {
return new NoRewindIterator($this->iterateBinary($bytes)); }
} 整個類源文件如下如示: class BigFile { protected $file;
public function __construct($filename, $mode = 'r') { if (!file_exists($filename)) {
throw new Exception('File not found');
}
$this->file = new SplFileObject($filename, $mode); }
protected function iterateText() { $count = 0;
while (!$this->file->eof()) {
yield $this->file->fgets();
$count++; } return $count; }
protected function iterateBinary($bytes) { $count = 0;
while (!$this->file->eof()) {
yield $this->file->fread($bytes);
$count++; } }
public function iterate($type = 'Text', $bytes = NULL) { if ($type == 'Text') {
return new NoRewindIterator($this->iterateText());
} else {
return new NoRewindIterator($this->iterateBinary($bytes)); }
} } 解析大文件: 我們對類文件做如下測試: $largefile = new BigFile('file.csv');
$iterator = $largefile->iterate('Text'); // Text or Binary based on your file type
foreach ($iterator as $line) {
echo $line;
} 現(xiàn)在這個類可以讀取任何尺寸的大文件,沒有任何限制,無限大。 我們可以在Laravel項目中,將該類添加到composer.json文件中自動加載該類并直接使用。 從此,我們可以輕松使用PHP解析和處理大尺寸文件了。 Happy PHP Coding! 作者:飛花逐月 |
|