PHPExcel 从大工作表中删除行
PHPExcel deleting rows from large worksheet
我正在尝试根据单元格 B = 59/61 等条件删除行。但是,PHPExcel 加载行的速度非常慢。对于包含 18000 rows/3MB 的工作表,加载大约需要 4 小时 30 分钟。如何提高数据工作表加载和删除的速度?
set_include_path(get_include_path() . PATH_SEPARATOR . 'Classes/');
/** PHPExcel_IOFactory */
include 'PHPExcel/IOFactory.php';
//Defining File Type
$fileType = "Excel2007";
//Retrieving File
$tmpfname = "bigfile.xlsx";
//Loading file into PHPExcel
$objPHPExcel = PHPExcel_IOFactory::load($tmpfname);
$worksheet = $objPHPExcel->getSheet(0); //Worksheet of file defined as first
$lastRow = $worksheet->getHighestRow();
//Determine which rows to be remove
$DeletedRows = [];
$DeletedRowCount = 0;
for ($row = 2; $row <= $lastRow; $row++) {
//Checker
$CellA = $worksheet->getCell('A' . $row)->getValue();
$CellB = $worksheet->getCell('B' . $row)->getValue();
$CellE = $worksheet->getCell('E' . $row)->getValue();
//To check condition
if ($CellB != 8 && $CellB != 9 && $CellB != 18 && $CellB != 19) {
$DeletedRows[] = $row;
continue;
}
//To check if condition
else if ($CellE == 59 || $CellE == 61){
$DeletedRows[] = $row;
continue;
}
}
//Removing the rows
//Deleting this way as when one row deleted, one row less.
foreach ($DeletedRows as $key => $value) {
$row = $value - $DeletedRowCount;
$objPHPExcel->getActiveSheet()->removeRow($row, 1);
$DeletedRowCount++;
}
//Write file into original file
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, $fileType);
$objWriter->save($tmpfname);
提高性能的一种方法是从电子表格底部向上而不是向下工作。
当您删除一行时,PHPExcel 必须检查其下方每一行中的单元格,并在必要时调整这些单元格中的引用。当您从工作表底部向上工作时,这样做效率更高,需要的 checks/updates 更少。
如果一次可以删除多行,效率也会高很多。如果需要删除第15、16、17行;然后
$objPHPExcel->getActiveSheet()->removeRow(15, 3);
比
快 3 倍
$objPHPExcel->getActiveSheet()->removeRow(15, 1);
$objPHPExcel->getActiveSheet()->removeRow(16, 1);
$objPHPExcel->getActiveSheet()->removeRow(17, 1);
因此,花一点时间评估您的 $DeletedRows
数组以寻找范围可能是有益的
如果不是在第一个循环中构建要删除的行号数组并在第二个循环中删除它们,而是在第一个循环中删除它们,那么您的代码也会快很多... 1 个循环将不可避免比 2 个循环快
最后,您的方法存在一个重大缺陷。如果您的第一个循环告诉您需要删除第 1、5 行;您删除第 1 行,然后删除第 5 行……除了第 5 行实际上是第 4 行,因为您删除了第 1 行,并且您实际上只是在执行原始循环以评估要删除的行时删除了第 6 行....从下到上工作可以防止这个问题并且更有效率
我正在尝试根据单元格 B = 59/61 等条件删除行。但是,PHPExcel 加载行的速度非常慢。对于包含 18000 rows/3MB 的工作表,加载大约需要 4 小时 30 分钟。如何提高数据工作表加载和删除的速度?
set_include_path(get_include_path() . PATH_SEPARATOR . 'Classes/');
/** PHPExcel_IOFactory */
include 'PHPExcel/IOFactory.php';
//Defining File Type
$fileType = "Excel2007";
//Retrieving File
$tmpfname = "bigfile.xlsx";
//Loading file into PHPExcel
$objPHPExcel = PHPExcel_IOFactory::load($tmpfname);
$worksheet = $objPHPExcel->getSheet(0); //Worksheet of file defined as first
$lastRow = $worksheet->getHighestRow();
//Determine which rows to be remove
$DeletedRows = [];
$DeletedRowCount = 0;
for ($row = 2; $row <= $lastRow; $row++) {
//Checker
$CellA = $worksheet->getCell('A' . $row)->getValue();
$CellB = $worksheet->getCell('B' . $row)->getValue();
$CellE = $worksheet->getCell('E' . $row)->getValue();
//To check condition
if ($CellB != 8 && $CellB != 9 && $CellB != 18 && $CellB != 19) {
$DeletedRows[] = $row;
continue;
}
//To check if condition
else if ($CellE == 59 || $CellE == 61){
$DeletedRows[] = $row;
continue;
}
}
//Removing the rows
//Deleting this way as when one row deleted, one row less.
foreach ($DeletedRows as $key => $value) {
$row = $value - $DeletedRowCount;
$objPHPExcel->getActiveSheet()->removeRow($row, 1);
$DeletedRowCount++;
}
//Write file into original file
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, $fileType);
$objWriter->save($tmpfname);
提高性能的一种方法是从电子表格底部向上而不是向下工作。
当您删除一行时,PHPExcel 必须检查其下方每一行中的单元格,并在必要时调整这些单元格中的引用。当您从工作表底部向上工作时,这样做效率更高,需要的 checks/updates 更少。
如果一次可以删除多行,效率也会高很多。如果需要删除第15、16、17行;然后
$objPHPExcel->getActiveSheet()->removeRow(15, 3);
比
快 3 倍$objPHPExcel->getActiveSheet()->removeRow(15, 1);
$objPHPExcel->getActiveSheet()->removeRow(16, 1);
$objPHPExcel->getActiveSheet()->removeRow(17, 1);
因此,花一点时间评估您的 $DeletedRows
数组以寻找范围可能是有益的
如果不是在第一个循环中构建要删除的行号数组并在第二个循环中删除它们,而是在第一个循环中删除它们,那么您的代码也会快很多... 1 个循环将不可避免比 2 个循环快
最后,您的方法存在一个重大缺陷。如果您的第一个循环告诉您需要删除第 1、5 行;您删除第 1 行,然后删除第 5 行……除了第 5 行实际上是第 4 行,因为您删除了第 1 行,并且您实际上只是在执行原始循环以评估要删除的行时删除了第 6 行....从下到上工作可以防止这个问题并且更有效率