За последние 24 часа нас посетили 21332 программиста и 1024 робота. Сейчас ищут 707 программистов ...

Парсер xls файла

Тема в разделе "Прочие вопросы по PHP", создана пользователем SergeWiz, 11 мар 2009.

  1. SergeWiz

    SergeWiz Активный пользователь

    С нами с:
    19 ноя 2008
    Сообщения:
    7
    Симпатии:
    0
    Добрый день

    Подскажите, пожалуйста, чем лучше парсить файл xls.
    Файлы большие (~3мб, ~15к строк и строки есть длинные, больше 255 символов, если сохраняю файл как csv, то такие строки заменяются на #### и парсить csv уже не имеет смысла)

    Благодарен за ответ
     
  2. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    PHPExcel!

    если нужны только данные из файла, то читать надо $reader->load(file, ReadDataOnly) чтобы не читались оформитеольские штучки. Эта возможность позволяет считывать в память только данные- меньше загружает память.

    можно парсить как по буквам, типа "А1", "B9", "F62:D76". А можно сделать что- то вроде $cells= $excel->activeSheet()->cellsAsArray() и получить массив ячеек, к которому можно обращаться по индексам $cell[1][2], $cells[6][21] и т.д.

    если завтра попросят перейти на xlsx, придется поменять всего одну строчку чтения файла в память, в весь "алгоритм парсинья" останется неизменным.
     
  3. Xerk

    Xerk Активный пользователь

    С нами с:
    5 окт 2007
    Сообщения:
    177
    Симпатии:
    0
    Адрес:
    Владивосток
    а памяти то хватит?
     
  4. SergeWiz

    SergeWiz Активный пользователь

    С нами с:
    19 ноя 2008
    Сообщения:
    7
    Симпатии:
    0
    да в том то и дело, что не хватает
    перепробовал уже кучу парсеров, с небольшими файлами работают прекрасно, при тестировании этих же файлов, но увеличенных в разы по количеству записей вылетает скрипт
    нужен парсер который берет только данные, не смотрит и не запоминает ни шрифты ячеек таблицы, ни стили, ни форматирования, ни объединения, ни что-либо еще
    я не могу поставить какие-то ограничения на размер файла или количество строк в нем, скрипт используется предприятиями, которые грузят прайс-листы запчастей для техники (у кого-то 5к наименований, у кого-то 25к)
    служба поддержки хостинга рекомендовали использовать csv, но там при сохранении строки более 255 символов заменяются на ###, хоть таких строк и немного, но все равно это уже не вариант
     
  5. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    если можно парсить ТОЛЬКО по буквам А, B то проблема решается легко.
     
  6. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    парсить по частям
     
  7. SergeWiz

    SergeWiz Активный пользователь

    С нами с:
    19 ноя 2008
    Сообщения:
    7
    Симпатии:
    0
    а как делить на части ? если вылетает ошибка о нехватке памяти уже на открытии файла парсером. вариант предложить клиентам грузить прайсы по 5 тысяч записей несколькими файлами не подходит, уж слишком навязчивый сервис получится:)
     
  8. vlad-net

    vlad-net Активный пользователь

    С нами с:
    28 июл 2006
    Сообщения:
    42
    Симпатии:
    0
    Адрес:
    Москва
  9. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    ты мне скажи ReadDataOnly не забыл указать?

    если и это не помогает, то можно посоветовать только увеличить доступную скрипту память allowed_memory_size в php.ini.

    все остальные парсеры в лучшем случае сделают что PHPExcel при ReadDataOnly. Так что сколько с ними не экспериментируй- не заработает.
     
  10. alexey_baranov

    alexey_baranov Активный пользователь

    С нами с:
    3 фев 2009
    Сообщения:
    647
    Симпатии:
    0
    Адрес:
    Сургут
    Беру свои слова обратно.

    PHPExcel и любая другая объектная библиотека не подходит для обработки таких файлов. Несложно посчитать
    • если в файле 20к строк по 15 колонок, то получается 300 000 ячеек.
      если в каждой строчке по 500 символов да каждый символ в юникоде весит два байта, то данных там всего на 20Мб.

    20 Мб- это конечно не много, но объектные библиотеки создают минимум по одному объекту на каждую ячейку. Даже если не читать оформления и пр. ненужности, все равно получается 300 000 тяжелых объектов.

    Если бы те же самые данные поместить в обычный массив в текстовом виде, это не требовало бы столько памяти. Поэтому для парсинья тысячников больше подойдет PHP-ExcelReader. Там как раз так все и устроено. например, данные хранятся вот так $xl_reader->sheets[0]['cells'][2][4]

    а PHPExcel протестил на 20k строках, в каждой 15 колонок, в одной из колонок число символов очень большое (до 400). Вот результат первый для ексель 2003, второй для 2007. В обоих случаях стоял $reader->setReadDataOnly(true)
    • 11:22:04 Load from Excel2003 file 11:30:28 Peak memory usage: 278.75 MB 11:30:28 Done.
      11:31:42 Load from Excel2007 file 11:38:33 Peak memory usage: 269 MB 11:38:34 Done.

    По этим данным можно расчитать максимальный размер экселевского файла, который можно парсить/генерить на хостинге при помощи PHPExcel. Например, если стоит ограничение памяти 128 Мб, то получится загрузить не больше
    • 20*128/269= 9.5k строк по 15 колонок
      или 20k строк но по 7 колонок
      или 4k строк по 30 колонок и т.д.

    Вот такие вот ограничения. Если же задача такая, что больших объемов там не бывает, все равно PHPExcel, потому что объектный стиль- это все- таки не sheets[0]['cells'][2][4]
     
  11. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    alexey_baranov
    Вывод один - PHPExcel писали дураки. Умные дураки. Слишком умные. "Горе от ума" блин.
     
  12. Novichek

    Novichek Активный пользователь

    С нами с:
    27 янв 2007
    Сообщения:
    16
    Симпатии:
    0
    А вы не подскажите, чем вы сейчас парсите?
    Я сейчас изучаю это http://code.google.com/p/php-excel-reader/ , из всего того, что пробовал самая не требовательная к памяти, если подключать файл с параметром "false":

    Код (Text):
    1. $xls = new Spreadsheet_Excel_Reader("$fileXLS",false);
    Ещё в файле excel_reader2.php, можно закоментировать строки:
    Код (Text):
    1.  
    2. if ($this->store_extended_info) {
    3.  
    4.     $this->sheets[$this->sn]['cellsInfo'][$row + $this->_rowoffset][$col + $this->_coloffset]['raw'] = $raw;
    5.  
    6.     $this->sheets[$this->sn]['cellsInfo'][$row + $this->_rowoffset][$col + $this->_coloffset]['type'] = $type;
    7.  
    8.     $this->sheets[$this->sn]['cellsInfo'][$row + $this->_rowoffset][$col + $this->_coloffset]['format'] = $format;
    9.  
    10.     $this->sheets[$this->sn]['cellsInfo'][$row + $this->_rowoffset][$col + $this->_coloffset]['formatIndex'] = $formatIndex;
    11. }
    это тоже сбережёт память, особенно если закоментированная инфа, вам не нужна.

    Скорее всего, вам ещё понадобится изменить кодировку, в моём случае так:
    Код (Text):
    1. var $_defaultEncoding = 'CP1251';
    Одна проблема у меня ещё с этим скриптом осталась, почему-то не все форматы ячеек считываются, вместо некоторых значений получаю "GENERAL". Разбираюсь... Если вы тоже будите разбираться с этим скриптом и найдёте решение, отпишите здесь или в личку, буду весьма признателен.
     
  13. Stream

    Stream Активный пользователь

    С нами с:
    13 май 2010
    Сообщения:
    1
    Симпатии:
    0
    Прошу прощения за некропостинг, но не смог самостоятельно решить проблему с кодировкой.
    Прописал:
    Код (Text):
    1. var $_defaultEncoding = 'CP1251';
    Но все равно вместо русских букв выводятся каракули.
    В php.ini прописан windows-1251, в apache прописан UTF-8 (почему то с такой комбинацией меньше всего проблем, но я пробовал по всякому - не помогло).
    Очень надеюсь, что поможете решить данную проблему.
     
  14. shogo

    shogo Активный пользователь

    С нами с:
    27 май 2010
    Сообщения:
    1
    Симпатии:
    0
    У меня тоже была проблема с кодировкой, вот так заработало:

    Код (Text):
    1. $data = new Spreadsheet_Excel_Reader();
    2. $data->setOutputEncoding('CP1251');
    3. $data->setUTFEncoder('mb');
    4. $data->read("example2.xls");
     
  15. entonee

    entonee Активный пользователь

    С нами с:
    18 авг 2010
    Сообщения:
    1
    Симпатии:
    0
    привет всем...
    у меня все получилось.. кодировку на странице сделал - UTF-8

    только 2(не русских, не англ.) символа заменяються на вопросики
    остальные показываються как есть

    вот пример - www.entonee.net/exel/example.php

    а вот и excel file - www.entonee.net/exel/jxlrwtest.xls

    -------

    может кто подскажет изза чего это.......? спасибо
     
  16. sbase

    sbase Активный пользователь

    С нами с:
    19 ноя 2010
    Сообщения:
    1
    Симпатии:
    0
    Создавать объект для каждой ячейки это действительно не очень хорошая идея, Excel_Spreadsheet_Reader прекрасно обходится без этого. Но если нужно всё равно перегнать всё в массив то можно просто заблокировать создание объекта ячейки.

    Для PHPExcel для чтения XLSX (Excel2007 reader) файлов я сделал маленький патч (злобный хак), там же образом ,думаю, можно оптимизировать другие ридеры.

    Решение с патчем загнал в их трекер.

    http://phpexcel.codeplex.com/workitem/14701

    Расход по памяти уменьшился в 7 раз (было 88 МБ - стало 12 МБ для 5 МБ файла).
    Возможно есть более красивое решение, но __мою__ задачу этот патч (злобный хак) решает.
     
  17. Coleman

    Coleman Активный пользователь

    С нами с:
    2 дек 2010
    Сообщения:
    1
    Симпатии:
    0
    Адрес:
    Москва
    Подскажите, а есть какие-нибудь библиотеки для доступа к таблицам в Excel файле через SQL интерфейс? По типу как это реализовано в ODBC