Ответ 1
Было много написано об использовании памяти PHPExcel на форуме PHPExcel; поэтому чтение некоторых из этих предыдущих обсуждений может дать вам несколько идей. PHPExcel хранит представление "в памяти" электронной таблицы и подвержено ограничениям памяти PHP.
Физический размер файла в значительной степени не имеет значения... гораздо важнее знать, сколько ячеек (строк * столбцов на каждом рабочем листе) оно содержит.
"Основное правило", которое я всегда использовал, составляет в среднем около 1 к/ячейку, поэтому в 5-мегабайтной рабочей книге потребуется 5 ГБ памяти. Однако есть несколько способов уменьшить это требование. Они могут быть объединены в зависимости от того, какую информацию вам нужно получить в своей книге, и что вы хотите с ней делать.
Если у вас несколько листов, но не нужно загружать их все, то вы можете ограничить листы, которые Reader загрузит, используя метод setLoadSheetsOnly(). Для загрузки одного именованного рабочего листа:
$inputFileType = 'Excel5';
$inputFileName = './sampleData/example1.xls';
$sheetname = 'Data Sheet #2';
/** Create a new Reader of the type defined in $inputFileType **/
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
/** Advise the Reader of which WorkSheets we want to load **/
$objReader->setLoadSheetsOnly($sheetname);
/** Load $inputFileName to a PHPExcel Object **/
$objPHPExcel = $objReader->load($inputFileName);
Или вы можете указать несколько листов с одним вызовом setLoadSheetsOnly(), передав массив имен:
$inputFileType = 'Excel5';
$inputFileName = './sampleData/example1.xls';
$sheetnames = array('Data Sheet #1','Data Sheet #3');
/** Create a new Reader of the type defined in $inputFileType **/
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
/** Advise the Reader of which WorkSheets we want to load **/
$objReader->setLoadSheetsOnly($sheetnames);
/** Load $inputFileName to a PHPExcel Object **/
$objPHPExcel = $objReader->load($inputFileName);
Если вам нужно только получить доступ к части рабочего листа, вы можете определить фильтр чтения, чтобы определить, какие ячейки вы хотите загрузить:
$inputFileType = 'Excel5';
$inputFileName = './sampleData/example1.xls';
$sheetname = 'Data Sheet #3';
/** Define a Read Filter class implementing PHPExcel_Reader_IReadFilter */
class MyReadFilter implements PHPExcel_Reader_IReadFilter {
public function readCell($column, $row, $worksheetName = '') {
// Read rows 1 to 7 and columns A to E only
if ($row >= 1 && $row <= 7) {
if (in_array($column,range('A','E'))) {
return true;
}
}
return false;
}
}
/** Create an Instance of our Read Filter **/
$filterSubset = new MyReadFilter();
/** Create a new Reader of the type defined in $inputFileType **/
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
/** Advise the Reader of which WorkSheets we want to load
It more efficient to limit sheet loading in this manner rather than coding it into a Read Filter **/
$objReader->setLoadSheetsOnly($sheetname);
echo 'Loading Sheet using filter';
/** Tell the Reader that we want to use the Read Filter that we've Instantiated **/
$objReader->setReadFilter($filterSubset);
/** Load only the rows and columns that match our filter from $inputFileName to a PHPExcel Object **/
$objPHPExcel = $objReader->load($inputFileName);
Используя фильтры чтения, вы также можете прочитать книгу в "кусках", так что только один блок является резидентным ядром в любой момент времени:
$inputFileType = 'Excel5';
$inputFileName = './sampleData/example2.xls';
/** Define a Read Filter class implementing PHPExcel_Reader_IReadFilter */
class chunkReadFilter implements PHPExcel_Reader_IReadFilter {
private $_startRow = 0;
private $_endRow = 0;
/** Set the list of rows that we want to read */
public function setRows($startRow, $chunkSize) {
$this->_startRow = $startRow;
$this->_endRow = $startRow + $chunkSize;
}
public function readCell($column, $row, $worksheetName = '') {
// Only read the heading row, and the rows that are configured in $this->_startRow and $this->_endRow
if (($row == 1) || ($row >= $this->_startRow && $row < $this->_endRow)) {
return true;
}
return false;
}
}
/** Create a new Reader of the type defined in $inputFileType **/
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
/** Define how many rows we want to read for each "chunk" **/
$chunkSize = 20;
/** Create a new Instance of our Read Filter **/
$chunkFilter = new chunkReadFilter();
/** Tell the Reader that we want to use the Read Filter that we've Instantiated **/
$objReader->setReadFilter($chunkFilter);
/** Loop to read our worksheet in "chunk size" blocks **/
/** $startRow is set to 2 initially because we always read the headings in row #1 **/
for ($startRow = 2; $startRow <= 65536; $startRow += $chunkSize) {
/** Tell the Read Filter, the limits on which rows we want to read this iteration **/
$chunkFilter->setRows($startRow,$chunkSize);
/** Load only the rows that match our filter from $inputFileName to a PHPExcel Object **/
$objPHPExcel = $objReader->load($inputFileName);
// Do some processing here
// Free up some of the memory
$objPHPExcel->disconnectWorksheets();
unset($objPHPExcel);
}
Если вам не нужно загружать информацию о форматировании, а только данные рабочего листа, то метод setReadDataOnly() скажет читателю только загрузить значения ячеек, игнорируя форматирование любой ячейки:
$inputFileType = 'Excel5';
$inputFileName = './sampleData/example1.xls';
/** Create a new Reader of the type defined in $inputFileType **/
$objReader = PHPExcel_IOFactory::createReader($inputFileType);
/** Advise the Reader that we only want to load cell data, not formatting **/
$objReader->setReadDataOnly(true);
/** Load $inputFileName to a PHPExcel Object **/
$objPHPExcel = $objReader->load($inputFileName);
Использовать кеширование. Это метод сокращения памяти PHP, который требуется для каждой ячейки, но со скоростью в скорости. Он работает путем хранения объектов ячейки в сжатом формате или за пределами памяти PHP (например, диска, APC, memcache)... но чем больше памяти вы сохраните, тем медленнее будут выполняться ваши скрипты. Тем не менее, вы можете уменьшить объем памяти, необходимый каждой ячейке, примерно до 300 байт, поэтому для гипотетических 5M-ячеек потребуется около 1,4 Гбайт памяти PHP.
Кэширование ячеек описано в разделе 4.2.1 Документации разработчика
ИЗМЕНИТЬ
Глядя на свой код, вы используете итераторы, которые не особенно эффективны и создают массив данных ячеек. Возможно, вы захотите посмотреть на метод toArray(), который уже встроен в PHPExcel, и делает это за вас. Также взгляните на это недавнее обсуждение на SO о новом варианте метода rangeToArray() для создания ассоциативного массива данных строк.