电竞比分网-中国电竞赛事及体育赛事平台

分享

使用PHP讀取和解析大文件實(shí)戰(zhàn)

 太極混元天尊 2018-05-20

21CTO導(dǎo)讀:在現(xiàn)在這篇文章中,我們將一起學(xué)習(xí)處理PHP中的大文件,避免因內(nèi)存限制而無法使用的方法。


如果你想用PHP處理大文件,PHP提供了一些普通的PHP函數(shù),比如file_get_contents()或file()函數(shù),它們?cè)谔幚沓笪募r(shí)會(huì)存在一定局限性。


其中包括:


1.內(nèi)存限制 


上面這些函數(shù)依賴于php.ini中memory_limit的參數(shù)值設(shè)置,可以調(diào)整增加這些值,但這些函數(shù)仍然不適合極大的文件,因?yàn)檫@些函數(shù)會(huì)把整個(gè)文件內(nèi)容都讀入到內(nèi)存中。


如果文件的尺寸超過memory_limit的設(shè)置,這類文件都不會(huì)加載到內(nèi)存中?,F(xiàn)實(shí)中,比如我們有一個(gè)20G的的文件,想用PHP來處理,該怎么樣處理?


2.不太好的用戶體驗(yàn)


還有一個(gè)限制是生產(chǎn)環(huán)境的速度問題。如果我們把它輸出到數(shù)組中,這樣經(jīng)常會(huì)出現(xiàn)在瀏覽器出現(xiàn)很長時(shí)間的等待,白頁或者出錯(cuò)等情況。這樣給用戶的體驗(yàn)不太好。


對(duì)于這種技術(shù)限制,可以使用yield關(guān)鍵字來直接生成一個(gè)結(jié)果。


SplFileObject Class


在本文中,我們告訴大家使用PHP標(biāo)準(zhǔn)庫中的SplFileObject類。


我們來演示,創(chuàng)建一個(gè)類來處理大文件。


這個(gè)類使用文件名做為輸入?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);

    }

 

}


接下來,我們定義一個(gè)遍歷文件的方法,這個(gè)方法將使用fgets()函數(shù)一次讀取文件一行。


我們也可以使用fread()函數(shù)的方法。


讀取文本文件


fgets()適用于解析包含換行符的文本文件,而fread()適用于解析二進(jìn)制文件。


該函數(shù)用于遍歷文本文件的每一行內(nèi)容。


protected function iterateText()

{

    $count = 0;

 

    while (!$this->file->eof()) {

 

        yield $this->file->fgets();

 

        $count++;

    }

    return $count;

}


讀取二進(jìn)制文件


來看另一個(gè)讀取二進(jìn)制的文件:


protected function iterateBinary($bytes)

{

    $count = 0;

 

    while (!$this->file->eof()) {

 

        yield $this->file->fread($bytes);

 

        $count++;

    }

}


直接讀取


現(xiàn)在我們將定義一個(gè)采用迭代的類型,返回NoRewindIterator實(shí)例的方法。


我們使用NoRewindIterator強(qiáng)制單向讀取。


public function iterate($type = 'Text', $bytes = NULL)

{

    if ($type == 'Text') {

 

        return new NoRewindIterator($this->iterateText());

 

    } else {

 

        return new NoRewindIterator($this->iterateBinary($bytes));

    }

 

}


整個(gè)類源文件如下如示:


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));

        }

 

    }

}


解析大文件:


我們對(duì)類文件做如下測(cè)試:


$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)在這個(gè)類可以讀取任何尺寸的大文件,沒有任何限制,無限大。


我們可以在Laravel項(xiàng)目中,將該類添加到composer.json文件中自動(dòng)加載該類并直接使用。


從此,我們可以輕松使用PHP解析和處理大尺寸文件了。


Happy PHP Coding!


作者:飛花逐月

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多