溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

PHP切割excel大文件的方法

發(fā)布時(shí)間:2020-08-25 14:36:48 來源:億速云 閱讀:216 作者:小新 欄目:編程語言

小編給大家分享一下PHP切割excel大文件的方法,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

利用phpspreadsheet可以輕松的解析excel文件,但是phpspreadsheet的內(nèi)存消耗也是比較大的,我試過解析將近5M的純文字excel內(nèi)存使用量就會超過php默認(rèn)的最大內(nèi)存128M。
當(dāng)然這可以用調(diào)節(jié)內(nèi)存大小的方法來解決,但是在并發(fā)量大的時(shí)候就比較危險(xiǎn)了。所以今天介紹下一種方法,利用phpspreadsheet對excel文件進(jìn)行切割,這是個(gè)拿時(shí)間換空間的方法所以一般對時(shí)效性要求低的需求可以使用。

方法:

  先放個(gè)phpspreadsheet官網(wǎng)提供的一個(gè)功能readCell,我們就可以利用這個(gè)功能來進(jìn)行切割。

  首先對excel文件進(jìn)行預(yù)讀,主要是獲取所有的工作表以及工作表下面的數(shù)據(jù)行數(shù),這個(gè)階段readCell方法一直返回的都是false,我們只需要記錄readCell進(jìn)來的工作表及數(shù)據(jù)行數(shù)。

  然后就是對獲取到的記錄進(jìn)行分析,確定每部分?jǐn)?shù)據(jù)需要裝多少行原始excel的數(shù)據(jù),需要注意的是為了避免內(nèi)容混淆,不要講兩個(gè)工作表的內(nèi)容切到一起。

  最后就是循環(huán)分析的數(shù)據(jù)和再次利用readCell獲取每部分?jǐn)?shù)據(jù),注意每次讀取文件后都要利用disconnectWorksheets方法清理phpspreadsheet的內(nèi)存。

  經(jīng)過我自己的測試發(fā)現(xiàn),利用該方法解析5M的excel文件,平均只需要21M的內(nèi)存就可以搞定!

代碼
<?php    
namespace CutExcel;    
require_once 'PhpSpreadsheet/autoload.php';    
/**    
 * 預(yù)讀過濾類    
 * @author wangyelou     
 * @date 2018-07-30    
 */    
class MyAheadreadFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter    
{    
    public $record = array();    
    private $lastRow = '';    
    public function readCell($column, $row, $worksheetName = '')     
    {    
        if (isset($this->record[$worksheetName]) ) {    
            if ($this->lastRow != $row) {    
                $this->record[$worksheetName] ++;           
                $this->lastRow = $row;    
            }     
        } else {    
            $this->record[$worksheetName] = 1;           
            $this->lastRow = $row;    
        }    
        return false;    
    }    
}    
/**    
 * 解析過濾類    
 * @author wangyelou     
 * @date 2018-07-30    
 */    
class MyreadFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter    
{    
    public $startRow;    
    public $endRow;    
    public $worksheetName;    
    public function readCell($column, $row, $worksheetName = '')     
    {    
        if ($worksheetName == $this->worksheetName && $row >= ($this->startRow+1) && $row <= ($this->endRow+1)) {    
            return true;    
        }    
        return false;    
    }    
}    
/**    
 * 切割類    
 * @author wangyelou     
 * @date 2018-07-30    
 */    
class excelCut    
{    
    public $cutNum = 5;    
    public $returnType = 'Csv';    
    public $fileDir = '/tmp/';    
    public $log;    
    /**    
     * 切割字符串    
     * @param $str    
     * @return array|bool    
     */    
    public function cutFromStr($str)    
    {    
        try {    
            $filePath = '/tmp/' . time() . mt_rand(1000, 9000) . $this->returnType;    
            file_put_contents($filePath, $str);    
            if (file_exists($filePath)) {    
                $result =  $this->cutFromFile($filePath);    
                unlink($filePath);    
                return $result;    
            } else {    
                throw new Exception('文件寫入錯(cuò)誤');    
            }    
        } catch (Exception $e) {    
            $this->log = $e->getMessage();    
            return false;    
        }    
    }    
    /**    
     * 切割文件    
     * @param $file    
     * @return array|bool    
     */    
    public function cutFromFile($file)    
    {    
        try {    
            $cutRules = $this->readaheadFromFile($file);    
            $dir = $this->getFileDir($file);    
            $returnType = $this->returnType ? $this->returnType : 'Csv';    
            $results = array();    
            //初始化讀    
            $myFilter = new MyreadFilter();    
            $inputFileType = \PhpOffice\PhpSpreadsheet\IOFactory::identify($file);    
            $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);    
            $reader->setReadDataOnly(true);    
            $reader->setReadFilter($myFilter);    
            foreach ($cutRules as $sheetName => $rowIndexRange) {    
                //讀    
                list($myFilter->startRow, $myFilter->endRow, $myFilter->worksheetName) = $rowIndexRange;    
                $spreadsheetReader = $reader->load($file);    
                $sheetData = $spreadsheetReader->setActiveSheetIndexByName($myFilter->worksheetName)->toArray(null, false, false, false);    
                $realDatas = array_splice($sheetData, $myFilter->startRow, ($myFilter->endRow - $myFilter->startRow + 1));    
                $spreadsheetReader->disconnectWorksheets();    
                unset($sheetData);    
                unset($spreadsheetReader);    
                //寫    
                $saveFile = $dir . $sheetName . '.' . $returnType;    
                $spreadsheetWriter = new \PhpOffice\PhpSpreadsheet\Spreadsheet();    
                foreach ($realDatas as $rowIndex => $row) {    
                    foreach ($row as $colIndex => $col) {    
                        $spreadsheetWriter->getActiveSheet()->setCellValueByColumnAndRow($colIndex+1, $rowIndex+1, $col);    
                    }    
                }    
                $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheetWriter, $returnType);    
                $writer->save($saveFile);    
                $spreadsheetWriter->disconnectWorksheets();    
                unset($spreadsheetWriter);    
                $results[] = $saveFile;    
            }    
            return $results;    
        } catch (Exception $e) {    
            $this->log = $e->getMessage();    
            return false;    
        }    
    }    
    /**    
     * 預(yù)讀文件    
     */    
    public  function readaheadFromFile($file)    
    {    
        if (file_exists($file)) {    
            //獲取統(tǒng)計(jì)數(shù)據(jù)    
            $myFilter = new MyAheadreadFilter();    
            $inputFileType = \PhpOffice\PhpSpreadsheet\IOFactory::identify($file);    
            $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);    
            $reader->setReadDataOnly(true); //只讀數(shù)據(jù)    
            $reader->setReadFilter($myFilter);    
            $spreadsheet = $reader->load($file);    
            //$sheetData = $spreadsheet->getActiveSheet()->toArray(null, false, false, false);    
            list($fileName,) = explode('.', basename($file));    
            $datas = array();    
            $averageNum = ceil(array_sum($myFilter->record) / $this->cutNum);    
            foreach ($myFilter->record as $sheetName => $count) {    
                for ($i=0; $i<ceil($count/$averageNum); $i++) {    
                    $datas[$fileName . '_' . $sheetName . '_' . $i] = array($i*$averageNum, ($i+1)*$averageNum-1, $sheetName);    
                }    
            }    
            return $datas;    
        } else {    
            throw new Exception($file . ' not exists');    
        }    
    }    
    /**    
     * 創(chuàng)建目錄    
     * @param $file    
     * @return bool|string    
     */    
    protected function getFileDir($file)    
    {    
        $baseName = basename($file);    
        list($name) = explode('.', $baseName);    
        $fullName = $name .'_'. time() . '_' . mt_rand(1000, 9999);    
        $path = $this->fileDir . $fullName . '/';    
        mkdir($path, 0777);    
        chmod($path, 0777);    
        if (is_dir($path)) {    
            return $path;    
        } else {    
            $this->log = "mkdir {$path} failed";    
            return false;    
        }    
    }    
}

以上是PHP切割excel大文件的方法的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI