Maison  >  Article  >  développement back-end  >  Comment couper de gros fichiers Excel avec PHP (code complet ci-joint)

Comment couper de gros fichiers Excel avec PHP (code complet ci-joint)

little bottle
little bottleavant
2019-04-26 15:35:314561parcourir

Cet article parle principalement de l'utilisation de phpspreadsheet pour découper de gros fichiers Excel. Il a une certaine valeur de référence. Les amis intéressés peuvent en apprendre davantage.

L'utilisation de phpspreadsheet peut facilement analyser des fichiers Excel, mais la consommation de mémoire de phpspreadsheet est également relativement importante. J'ai essayé d'analyser près de 5 M de texte pur Excel, et l'utilisation de la mémoire dépassera la mémoire maximale par défaut de php. 128M.
Bien sûr, cela peut être résolu en ajustant la taille de la mémoire, mais c'est plus dangereux lorsque le nombre de concurrence est important. Aujourd'hui, je vais donc présenter la méthode suivante, utiliser phpspreadsheet pour couper des fichiers Excel. Il s'agit d'une méthode d'échange de temps contre de l'espace, elle peut donc généralement être utilisée pour des exigences de rapidité limitées.

Méthode :

Mettez d'abord une fonction readCell fournie par le site officiel de phpspreadsheet, nous pouvons utiliser cette fonction pour effectuer une découpe.

Tout d'abord, pré-lisez le fichier Excel, principalement pour obtenir toutes les feuilles de calcul et le nombre de lignes de données sous la feuille de calcul. À ce stade, la méthode readCell renvoie toujours false. Il suffit d'enregistrer la feuille de calcul qui readCell. entre. et le nombre de lignes de données.

L'étape suivante consiste à analyser les enregistrements obtenus et à déterminer combien de lignes de données Excel originales doivent être chargées dans chaque partie des données. Il convient de noter que afin d'éviter toute confusion dans le contenu, ne coupez pas. le contenu des deux feuilles de travail ensemble.

La dernière étape consiste à parcourir les données analysées et à utiliser à nouveau readCell pour obtenir chaque partie des données. Notez qu'à chaque fois que le fichier est lu, la méthode disconnectWorksheets doit être utilisée pour nettoyer la mémoire de phpspreadsheet. .

Après mes propres tests, j'ai découvert que l'utilisation de cette méthode pour analyser un fichier Excel de 5 Mo ne nécessite qu'une moyenne de 21 Mo de mémoire !

Code

<?php    
namespace CutExcel;    
require_once &#39;PhpSpreadsheet/autoload.php&#39;;    
/**    
 * 预读过滤类    
 * @author wangyelou     
 * @date 2018-07-30    
 */    
class MyAheadreadFilter implements \PhpOffice\PhpSpreadsheet\Reader\IReadFilter    
{    
    public $record = array();    
    private $lastRow = &#39;&#39;;    
    public function readCell($column, $row, $worksheetName = &#39;&#39;)     
    {    
        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 = &#39;&#39;)     
    {    
        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 = &#39;Csv&#39;;    
    public $fileDir = &#39;/tmp/&#39;;    
    public $log;    
    /**    
     * 切割字符串    
     * @param $str    
     * @return array|bool    
     */    
    public function cutFromStr($str)    
    {    
        try {    
            $filePath = &#39;/tmp/&#39; . 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(&#39;文件写入错误&#39;);    
            }    
        } 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 : &#39;Csv&#39;;    
            $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 . &#39;.&#39; . $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;    
        }    
    }    
    /**    
     * 预读文件    
     */    
    public  function readaheadFromFile($file)    
    {    
        if (file_exists($file)) {    
            //获取统计数据    
            $myFilter = new MyAheadreadFilter();    
            $inputFileType = \PhpOffice\PhpSpreadsheet\IOFactory::identify($file);    
            $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($inputFileType);    
            $reader->setReadDataOnly(true); //只读数据    
            $reader->setReadFilter($myFilter);    
            $spreadsheet = $reader->load($file);    
            //$sheetData = $spreadsheet->getActiveSheet()->toArray(null, false, false, false);    
            list($fileName,) = explode(&#39;.&#39;, 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 . &#39;_&#39; . $sheetName . &#39;_&#39; . $i] = array($i*$averageNum, ($i+1)*$averageNum-1, $sheetName);    
                }    
            }    
            return $datas;    
        } else {    
            throw new Exception($file . &#39; not exists&#39;);    
        }    
    }    
    /**    
     * 创建目录    
     * @param $file    
     * @return bool|string    
     */    
    protected function getFileDir($file)    
    {    
        $baseName = basename($file);    
        list($name) = explode(&#39;.&#39;, $baseName);    
        $fullName = $name .&#39;_&#39;. time() . &#39;_&#39; . mt_rand(1000, 9999);    
        $path = $this->fileDir . $fullName . &#39;/&#39;;    
        mkdir($path, 0777);    
        chmod($path, 0777);    
        if (is_dir($path)) {    
            return $path;    
        } else {    
            $this->log = "mkdir {$path} failed";    
            return false;    
        }    
    }    
}

Tutoriels associés : Tutoriel vidéo PHP

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer

Articles Liés

Voir plus