Tengo grandes hojas de trabajo de Excel que quiero poder leer en MySQL usando PHPExcel.¿Cómo leer hojas de cálculo grandes de grandes archivos de Excel (27 MB +) con PHPExcel?
Estoy usando el recent patch que le permite leer en las hojas de trabajo sin abrir todo el archivo. De esta manera puedo leer una hoja de trabajo a la vez.
Sin embargo, un archivo de Excel tiene 27 MB de tamaño. Puedo leer con éxito en la primera hoja de trabajo, ya que es pequeña, pero la segunda es tan grande que la tarea cron que inició el proceso a las 22:00 no terminó a las 8:00 a.m., la hoja de trabajo es demasiado grande.
¿Hay alguna forma de leer en una línea de trabajo por línea, p. algo como esto:
$inputFileType = 'Excel2007';
$inputFileName = 'big_file.xlsx';
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
$worksheetNames = $objReader->listWorksheetNames($inputFileName);
foreach ($worksheetNames as $sheetName) {
//BELOW IS "WISH CODE":
foreach($row = 1; $row <=$max_rows; $row+= 100) {
$dataset = $objReader->getWorksheetWithRows($row, $row+100);
save_dataset_to_database($dataset);
}
}
Adición
@ Marcos, he utilizado el código que envió para crear el siguiente ejemplo:
function readRowsFromWorksheet() {
$file_name = htmlentities($_POST['file_name']);
$file_type = htmlentities($_POST['file_type']);
echo 'Read rows from worksheet:<br />';
debug_log('----------start');
$objReader = PHPExcel_IOFactory::createReader($file_type);
$chunkSize = 20;
$chunkFilter = new ChunkReadFilter();
$objReader->setReadFilter($chunkFilter);
for ($startRow = 2; $startRow <= 240; $startRow += $chunkSize) {
$chunkFilter->setRows($startRow, $chunkSize);
$objPHPExcel = $objReader->load('data/' . $file_name);
debug_log('reading chunk starting at row '.$startRow);
$sheetData = $objPHPExcel->getActiveSheet()->toArray(null, true, true, true);
var_dump($sheetData);
echo '<hr />';
}
debug_log('end');
}
Como muestra el siguiente archivo de registro, se ejecuta bien en un pequeño archivo de Excel 8K, pero cuando lo ejecuto en un archivo de Excel 3 MB, nunca pasa el abeto st trozo, ¿hay alguna manera de que pueda optimizar el código para el funcionamiento, de lo contrario, no parece que no es suficiente para conseguir performant trozos de un gran archivo de Excel:
2011-01-12 11:07:15: ----------start
2011-01-12 11:07:15: reading chunk starting at row 2
2011-01-12 11:07:15: reading chunk starting at row 22
2011-01-12 11:07:15: reading chunk starting at row 42
2011-01-12 11:07:15: reading chunk starting at row 62
2011-01-12 11:07:15: reading chunk starting at row 82
2011-01-12 11:07:15: reading chunk starting at row 102
2011-01-12 11:07:15: reading chunk starting at row 122
2011-01-12 11:07:15: reading chunk starting at row 142
2011-01-12 11:07:15: reading chunk starting at row 162
2011-01-12 11:07:15: reading chunk starting at row 182
2011-01-12 11:07:15: reading chunk starting at row 202
2011-01-12 11:07:15: reading chunk starting at row 222
2011-01-12 11:07:15: end
2011-01-12 11:07:52: ----------start
2011-01-12 11:08:01: reading chunk starting at row 2
(...at 11:18, CPU usage at 93% still running...)
Adición 2
Cuando comento hacia fuera:
//$sheetData = $objPHPExcel->getActiveSheet()->toArray(null, true, true, true);
//var_dump($sheetData);
Luego se analiza a una velocidad aceptable 10 (aproximadamente 2 filas por segundo), ¿hay alguna manera de aumentar el rendimiento de toArray()
?
2011-01-12 11:40:51: ----------start
2011-01-12 11:40:59: reading chunk starting at row 2
2011-01-12 11:41:07: reading chunk starting at row 22
2011-01-12 11:41:14: reading chunk starting at row 42
2011-01-12 11:41:22: reading chunk starting at row 62
2011-01-12 11:41:29: reading chunk starting at row 82
2011-01-12 11:41:37: reading chunk starting at row 102
2011-01-12 11:41:45: reading chunk starting at row 122
2011-01-12 11:41:52: reading chunk starting at row 142
2011-01-12 11:42:00: reading chunk starting at row 162
2011-01-12 11:42:07: reading chunk starting at row 182
2011-01-12 11:42:15: reading chunk starting at row 202
2011-01-12 11:42:22: reading chunk starting at row 222
2011-01-12 11:42:22: end
adición 3
Esto parece funcionar adecuadamente, por ejemplo, al menos en el archivo 3 MB:
for ($startRow = 2; $startRow <= 240; $startRow += $chunkSize) {
echo 'Loading WorkSheet using configurable filter for headings row 1 and for rows ', $startRow, ' to ', ($startRow + $chunkSize - 1), '<br />';
$chunkFilter->setRows($startRow, $chunkSize);
$objPHPExcel = $objReader->load('data/' . $file_name);
debug_log('reading chunk starting at row ' . $startRow);
foreach ($objPHPExcel->getActiveSheet()->getRowIterator() as $row) {
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false);
echo '<tr>';
foreach ($cellIterator as $cell) {
if (!is_null($cell)) {
//$value = $cell->getCalculatedValue();
$rawValue = $cell->getValue();
debug_log($rawValue);
}
}
}
}
El var_dump de $ sheetData era sólo en mi fragmento de código para demostrar cómo funciona el chunking, probablemente no es algo que había necesidad de una utilización "mundo real". El método rangeToArray() que actualmente estoy agregando a la clase Hoja de trabajo también sería más eficiente que el método toArray() si tuviera que hacer un volcado de datos de la hoja de trabajo. –
@Edward Tanguay hola, ¿encontró alguna solución/alternativa para esto? Tengo el mismo problema –
Una alternativa a PHPExcel es la biblioteca de código abierto [Spout] (https://github.com/box/spout). Es compatible con la lectura y escritura de archivos de gran tamaño, y no requiere más de 10 MB de memoria. ¡Y es super rápido! – Adrien