이 기사는 주로 phpspreadsheet를 사용하여 대용량 Excel 파일을 자르는 것에 대해 설명합니다. 관심 있는 친구들이 이에 대해 배울 수 있기를 바랍니다.
phpspreadsheet를 사용하면 엑셀 파일을 쉽게 파싱할 수 있지만, phpspreadsheet의 메모리 소모도 상대적으로 큽니다. 순수 텍스트 엑셀을 5M 가까이 파싱하려고 했더니 메모리 사용량이 기본 최대 메모리를 초과하게 됩니다. 128M의 PHP.
물론 메모리 크기를 조절하면 해결이 되지만 동시성 양이 클수록 위험합니다. 그래서 오늘은 phpspreadsheet를 사용하여 Excel 파일을 자르는 다음 방법을 소개하겠습니다. 이는 시간을 공간으로 교환하는 방법이므로 일반적으로 적시성이 낮은 요구 사항에 사용할 수 있습니다.
먼저 phpspreadsheet 공식 웹사이트에서 제공하는 readCell 함수를 넣고, 이 함수를 사용하여 자르기를 수행할 수 있습니다.
먼저 Excel 파일을 미리 읽어서 주로 모든 워크시트와 워크시트 아래의 데이터 행 수를 가져옵니다. 이 단계에서는 readCell 메서드가 항상 false를 반환하면 됩니다. readCell의 데이터. 워크시트 및 데이터 행의 수입니다.
다음 단계는 획득한 기록을 분석하고 데이터의 각 부분에 로드해야 하는 원본 Excel 데이터의 행 수를 결정하는 것입니다. 내용 혼란을 피하기 위해 다음을 수행해야 합니다. 두 워크시트의 내용을 함께 자르지 마세요.
마지막 단계는 분석된 데이터를 반복하고 readCell을 다시 사용하여 데이터의 각 부분을 얻는 것입니다. 파일을 읽을 때마다 DisconnectWorksheets 메서드를 사용하여 메모리를 정리해야 합니다. phpspreadsheet의.
직접 테스트한 결과 이 방법을 사용하여 5M Excel 파일을 구문 분석하는 데는 평균 21M의 메모리만 필요하다는 사실을 발견했습니다!
<?php namespace CutExcel; require_once 'PhpSpreadsheet/autoload.php'; /** * 预读过滤类 * @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('文件写入错误'); } } 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; } } /** * 预读文件 */ 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('.', 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'); } } /** * 创建目录 * @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 비디오 튜토리얼
위 내용은 PHP로 대용량 엑셀 파일 잘라내는 방법(완전한 코드 첨부)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!