Как стать автором
Обновить

Комментарии 11

Вы копируете значения ячейка-за-ячейкой, но можно проще — копировать лист целиком: gist.github.com/pqr/ad12493947e7b1e2910f/82db011d811606bdf109b4d6addeb25517ca5342
//Берём лист из оригинального файла
$sheet = $sheetsIterator->current();
//"Перекладываем" его в PhpExcel объект, который потом будет сохранён в CSV
$csvPagePhpExcel->addSheet($sheet, 0);

В примечание к своему примеру скажу, что помимо метода addSheet() есть ещё addExternalSheet() — в общем случае более верным будет использовать именно addExternalSheet(), т.к. он копирует ещё и стили, которые хранятся не в объекте $sheet, а в самом workbook. Но для данной задачи вывода в CSV стили не важны, поэтому использование addSheet() будет быстрее и проще.

Разница с вашим кодом есть: копируя листы целиком, я никак не могу задать форма вывода дат. Будет использован некий формат «по умолчанию», который может отличаться от файла к файлу. Я попробовал два файла из своих реальных таблиц, в одном из них был FORMAT_DATE_XLSX14, в другом FORMAT_DATE_YYYYMMDD2.
Второе отличие: в вашем коде происходит хитрая проверка на ошибки в формулах (которые могут ссылаться на внешние книги), в моём варианте этих проверок нет.

Провёл тест вашего кода и своего кода на большом файле из 170 листов и 9.5 Мб результирующего CSV текста:
ваш вариант: 3221 сек
мой вариант: 347 сек.

p.s. пока писал комментарий, подумал, что перекладывать лист в промежуточный PhpExcel объект для записи в CSV вообще не обзательно, можно писать в CSV на лету из исходного PhpExcel объекта, двигая указатель текущего листа ($objWriter->setSheetIndex($sheetsIterator->key())): gist.github.com/pqr/ad12493947e7b1e2910f/1698b405fb511b4fc625a95139d3c23c3a21bd5d
отработал за 321 сек.

Наконец, не плохо было бы установить флаг $objReader->setReadDataOnly(true): gist.github.com/pqr/ad12493947e7b1e2910f/dd57ff58a2f7952e5beae491d95b3c8bc378dd66
отработал за 152 сек.

Согласен, можно получить итератор страницы и сразу сохранить его в нужном формате, но в данном случае мне критически важно было форматирование дат, и передача всех данных в новый документ. При чём шаблоны входящих документов могут быть разными и при этом мне не обязательно знать заранее в какой колонке будут находиться даты, а в какой простой текст.

К чему приводит установка флага setReadDataOnly(true), то есть какую ещё пользу он несёт кроме запрета изменения данных?
setReadDataOnly(true) — это не запрет на изменение, это команда для ридера «прочитай из исходного файла только данные без стилей» — ускоряет чтение, уменьшает потребление памяти. О нём, кстати, написано в той статье Универсальное чтение ячеек в PHPExcel
Понятно, спасибо, но в данном случае этот режим мне тоже не подходит так-как мы не сможем получить правильно дату.
А какой смысл кусков кода из манула, если Вы принципиально нового ничего не придумали и не показали? Т.е. это все есть в мануале и никаких фич здесь нет.
Смысл в том что это уже готовое решение, для експорта в Excel есть куча мануалов — каких только хочешь, а для данного процесса нигде ничего нет. Я сам неоднократно был близок к переходу на PHPExcel но из-за необязательности получения данных НЕ из первой страницы документа просто нехотел переходить на эту библиотеку только из-за того что она была для меня новая и я не знал на сколько просто с ней работать пока сам не разобрался. И из-за этого лепил велосипеды через fputcsv которые иногда были не очень то «ровными». А сколько людей до сих пор не могут начать делать то же самое пока не увидят подходящий вариант.
Ещё про смысл
А какой смысл кусков кода из манула, если Вы принципиально нового ничего не придумали и не показали? Т.е. это все есть в мануале и никаких фич здесь нет.

А какой смысл выкладывать здесь какие-то решения если всё можно выучить самостоятельно по мануалам, давайте всех новичков тыкать в мануалы как это делают на огромном количестве форумов. Вместо того что бы ответить на конкретно поставленный вопрос или хотя бы указать направление в котором нужно «копать» — каждый считает своим долгом сначала «оскорбить» вопрошающего, а через нескользо страниц гадостей возможно дать ответ. Я считаю что не нужно уподобаться им и судя по количеству людей которые добавили мою публикацию в избранное — всё таки смысл в ней есть.
Методом подбора я указал версию 1.8 с добавлением признака «неточности».

Элементарно, Ватсон:
https://packagist.org/packages/phpoffice/phpexcel

Кстати, замеры производительности этой библиотеки делали?
Спасибо за ссылку на packagist
По поводу замеров — кое что можно прочитать здесь Реализация быстрого импорта из Excel на PHP как я понимаю это не саммая быстрая либа, но из бесплатных только она может работать с xlsx форматом, поправьте меня если я не прав.
Это хорошая либа, но она достаточно быстро деградирует по производительности при росте количества элементов на листе / количества листов.

Быстро и полностью совместимо с Excel — только так:

new COM("Excel.Application", NULL, CP_UTF8);


На Windows-сервере, конечно же.
Есть неплохая библиотека, которая может составить конкуренцию PHPExcel в разборе файлов: github.com/box/spout
На простых (и больших) файлах работает отлично. На чем-то сложном проверить не пришлось. Если у кого-нибудь появится опыт — прошу поделиться.
Спасибо, По возможности протестирую, синтаксис очень похож на PHPExcel правда смущает что в инструкции к либе есть итераторы но они обходятся через foreach (правда это не запрещено, но всё же)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории