когда объединяется "гений" Microsoft и "гений" PHP результаты по убогости превосходят даже самые пессимистичные ожидания.
библиотека: PHPExcel
http://phpexcel.codeplex.com/файл: 15Мb.xls (Excel2005) - почти миллион ячеек (почти 60k строк)
устанавливается фильтр загрузки (setReadFilter) ячеек, пропускающий все ячейки (return false)
расход памяти: 112Mb
время работы: 2.5 минуты
O_o
ещё раз для тех, кто не понял: из файла согласно фильтру не загружается НИ ОДНОЙ ячейки данных, но память засирается почти на сто метров.
ок, включил опцию "загружать только данные" (setReadDataOnly(true)), которая исключает создание объектов форматирования ячеек. хотя по логике, если ячейки не загружаются, то их форматы тоже не должны загружаться.
расход: 60Mb.
прекрасная библиотека "для работы в standalone PHP applications" :)
в попытке разобраться куда же уходят лучшие байты моей памяти обнаружил прекрасную статью про расход памяти в PHP.
http://nikic.github.com/2011/12/12/How-big-are-PHP-arrays-really-Hint-BIG.htmlя был в курсе, что хранение данных в PHP мягко говоря не совсем оптимальное, но накладные расходы в 144 байта на каждый элемент массива (на 64-битной системе) это уже перебор. можно трактовать это как прямое указание выключать на 64-битных системах garbage collector (ini_set('gc_enable', false))
собственно, это первая статья расходов, внутри PHPExcel считывается разделяемая таблица строк, (которая в .xls хранится в виде последовательности Pascal-строк и занимает всего 100к), далее эта таблица распаковывается в массив элементов вида (строка, формат), который кушает 15 мегабайт сходу. форматы, напомню, согласно установке ReadDataOnly считываться не должны.
в общем, методика "хранить массивы строк в виде нераспакованной длинной строки", описанная тут
http://markmaunder.com/2012/06/19/php-array-is-a-little-scary/реально экономит память и, на таких больших размерах, время тоже.
дальше, мелочи вроде хранения неиспользуемых для работы данных из файла,
фрагментации памяти из-за сборки потока workbook из OLE блоков путём строковой конкатенации, вместо implode, использование SplFixedArray,
фикс утечек памяти ...
в общем удалось снизить расход до 28Mb, тоже не фонтан, но хотя бы в лимит помещается.
ссылки на полезные утилиты
(программистам)
https://github.com/okfn/dataproxy XLS/CSV/GoogleSpreadsheet -> JSON gateway
www.libxl.com/ - платная C++ библиотека для быстрой обработки больших XLS, есть расширение под PHP, которое её использует
(юзерам)
https://apps.synesty.com/transformy - офигенская утилита для быстрого online преобразования xls/ods/csv включая редактирование колонок по формулам (скоро будет
поддержка workflow)
http://www.zamzar.com/ - тоже самое, но поддерживается чуть больше форматов (
http://www.zamzar.com/conversionTypes.php) и без редактирования