В публикации показаны приемы по загрузке данных из файла Excel в таблицу значений..
Протестировано на версии платформы 1С:Предприятие 8.3 (8.3.9.1818).
В версии 8.3 для загрузки из Excel существует альтернатива COM объекту. У табличного документа есть метод Прочитать.
Особенно актуально для файлов больших объемов, т.к. табличный документ обрабатывается гораздо быстрее.
А табличный документ легко трансформируется в таблицу значений через построитель запроса.
Во вложении обработка — пример загрузки и вывода в табличный документ и таблицу значений.
Рабочий код занимает несколько строк:
//Вывод в табличный документ
ТабличныйДокумент = Новый ТабличныйДокумент;
ТабличныйДокумент.Прочитать(Файл, СпособЧтенияЗначенийТабличногоДокумента.Значение);
//вывод в таблицу значений
ПЗ = Новый ПостроительЗапроса;
ПЗ.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТабличныйДокумент.Область());
ПЗ.ДобавлениеПредставлений = ТипДобавленияПредставлений.НеДобавлять;
ПЗ.ЗаполнитьНастройки();
ПЗ.Выполнить();
ТаблицаЗначений = ПЗ.Результат.Выгрузить();
P.S. При выводе в таблицу значений через построитель запроса, названия колонок в источнике данных должны быть первой строкой, иначе построитель не сможет получить и преобразовать их в колонки таблицы значений и выдаст ошибку.
Во внешней обработке демонстрация загрузки.
Как воспримет построитель вот такие найменования колонок например:
Наименование товара
Кол-во
Дата документа
(1) воспримет нормально, но переименует по-своему ))
вот так
НаименованиеТовара
Кол_во
ДатаДокумента
Допустим требуется заполнить реквизит Артикул справочника номенклатура. Исходный файл содержит соответствующую колонку с текстом «000123», «000124» и т.п. все символы цифровые. Какое значение попадёт в строковый реквизит номенклатуры?
Если «123», «124» и т.п., то приемы эффективной загрузки данных из Excel в 1С разбиваются о реальность ))
Попадет значение «000123».
(3) Попадет значение «000123».
У меня проблема в методе «Прочитать()» , ядро 8.3.10.2580 : при загрузке больших файлов (2-3 Mb) расход памяти сервера может достигать 12 Gb
пришлось отказаться от этого метода и пользоваться ADODB
(4) Спасибо за эксперимент, пересмотрю своё мнение об этом методе. Мои опыты приводили к потере лидирующих нулей.
(7) возможно что-то уже изменили в платформе
и еще есть один нюанс. У метода Прочитать есть второй параметр СпособЧтенияЗначений.
<СпособЧтенияЗначений> (необязательный)
Тип: СпособЧтенияЗначенийТабличногоДокумента.
Определяет, каким образом нужно интерпретировать значения, считываемые из исходного документа XLS, XLSX или ODS.
При загрузке табличного документа из формата Excel 97 — 2010 и OpenOffice Calc, в случае если в ячейке исходного документа содержалось значение типа Дата или Число, то в ячейку результирующего табличного документа это значение попадает в зависимости от значения этого параметра.
Значение по умолчанию: Текст.
(6) обидно )) но что поделаешь
Спасибо, познавательно!
(9) Не обидно, а вопрос: Это ошибка платформы (т.к. не может из файла 2 Mb появиться файл mxl объемом 11Gb) или я что-то не так делаю?
(11) да интересно ) если хотите, отправьте мне этот файл. Я попробую его загрузить. Если конечно там нет конфиденциальной информации.
(11) А если на этом же сервере запустить тонкий клиент и через «Файл — Открыть» открыть этот файл? Расход памяти такой же будет?
а зачем построитель?
Можно по циклу обойти Табличный документ.
табличные документы 1С много «весят» — это особенно ощутимо для больших данных.
покрутите предлагаемый метод для эксель-файлов с сотнями тысяч строк, интересно за какое время вы прочтете
(14) можно и циклом. Это альтернативный способ. Мне больше нравится через построитель.
(15) вот результат замера. 1 млн. строк, файл excel 25 мб.
Время начала чтения табличного документа: 14.12.2017 10:24:40
Время окончания чтения табличного документа: 14.12.2017 10:26:31
Количество секунд чтения: 111
Время начала выгрузки табличного документа в ТЗ: 14.12.2017 10:26:37
Время окончания выгрузки табличного документа в ТЗ: 14.12.2017 10:26:49
Количество строк таблицы значений: 1 000 000
Количество секунд выгрузки: 12
Забавно. Попробуем.
(12) Вот файл
(13) Попробовал через тонкий клиент. Расход памяти такой же.
Кто то узнал о существовании построителя. Круто.
(16) я думаю, из-за построителя и расход памяти поболее будет.
(23) сам не замерял, но вполне возможно )
(19) вот результат. Обработал за 2 сек )) размер mxl файла 3 Мб.
Время начала чтения табличного документа: 14.12.2017 13:52:46
Время окончания чтения табличного документа: 14.12.2017 13:52:48
Количество секунд чтения: 2
Время начала выгрузки табличного документа в ТЗ: 14.12.2017 13:52:48
Время окончания выгрузки табличного документа в ТЗ: 14.12.2017 13:52:49
Количество строк таблицы значений: 11 874
Количество секунд выгрузки: 1
(26) там немного про другое, но в комментариях да, упоминается про метод Прочитать.
А где приемы? Я насчитал только один! Отчитали и накрыли построителем, а остальные ?
(28) ну вот и получается загрузка в 2 приема ))
Рассмотреть все возможные варианты работы с Excel не являлось целью публикации. Я просто хотел показать как можно с наменьшими затратами, используя код в несколько строк выполнить задачу.
Был небольшой опыт:
Когда попытался обработать через «прочитать» сохраненную контрагентом печатную форму с графическими объектами, все это дело просто повесилось. Пока что ADO и COM-объекты в таких случаях надежнее.
Спасибо! Очень интересный способ.
Насколько я понял, он не требует наличия на компьютере Microsoft Excel или OpenOffice Calc для чтения соответствующих таблиц?
Метод Табличного Документа «Записать» точно не требует, проверено)
(30) да, в таком случае лучше ADO.
Я не проверял, но думаю должен работать.
(31) Я не проверял, но думаю должен работать.
(22) Ага, ещё бы при чтении некоторых эксель-файлов не вылетало с ошибкой и страницы бы читала.
Хороший метод, только вот не работает с файлами эксель с расширением xlm, который с макросами. И Данные с нескольких страниц помещает в один табличный документ.
Спасибо. Статья помогла!
Просто и полезно. Укажите в публикации, пожалуйста, что это работает начиная с платформы версии 8.3.6, а с версии 8.3.10 можно грузить данные с определенного листа. Можно так же подкрепить ссылка на ИТС
Гениально. Не знал про такие фокусы с построителем и табличным документом.
(41) Тоже не знал) До сих пор ADO/EXCEL юзаю =)
(31) на сколько мне известно в 1С есть встроенный механизм работы с табличными документами, и в данном случае работает как раз встроенный механизм и получается приложение необязательное.
(44) Спасибо за дополнение 🙂 У вас отлично реализовано. Думаю будет очень полезно.
(44) А что за объект КэшФункции в функции ТекстОбластиЛиста?
И в строке Ф = НовыйФайл(ФайлExcel); пробел не пропущен НовыйФайл?
(46) Да, точно
Тут же в модуле
Показать
А КэшФункции — это модуль, закешированный на сеанс. Там, в том числе, закешированы типы данных:
Показать
На основании публикации доработал и свой модуль. Теперь выгружаю и в ТЗ.
Показать
(45) Я недавно сравнивал скорость загрузки через ADO и с помощью метода
Область = ЛистЭксель.Range(…);
Данные = Область.Value.Выгрузить();
Получилось, что второй метод быстрее ADO где то на 25%
Вы не сравнивали метод Range с вашим методом загрузки ? Что быстрее и насколько. Может сравните для полноты ощущений …?
Раз уж Вы пишете «Приемы эффективной загрузки …» , наверно необходимо сравнение с другими существующими . Иначе это может быть и «не эффективной загрузки».
Есть метод:
Вы не сравнивали метод Range с вашим методом загрузки ? Что быстрее и насколько ?
(59)
Данные = Область.Value.Выгрузить();
Попробовал на 1 млн. строк.
Время выполнения чтения файла вашим методом 36 сек. Время выполнения методом описанным в моей публикации 193 сек. Разница в 5 раз 🙂 Но ваш метод возвращает массивы значений, надо попробовать их разобрать.
(65) Так ожидаемо, что ТабДоком медленнее. И значительно тяжелее, наверное, по расходу памяти.
Но профит в том, что не нужен Excel, ADO-провайдеры. Пожалуй, только из-за этого на табдоки перебрался.
(66)
Конечно, если время выполнения приемлемое, то почему бы и нет.
(65)
Все уже разобрано…. Есть публикации вместе с кодом на инфостарте.
Хех, недолго радовался:( Придется отказаться от такого чтения. Тесты в боевых условиях валятся по нехватке памяти. Похоже, чтение ТабДоком сильно не любит формулы.
(69) Да, жаль )
(70) Для справки. Тесты гонял на 8.3.10.2580, 32-бит.
Так что, народ, аккуратнее с загрузкой ТабДоком…
Не могу понять, вашим методом загружается ли гиперссылка из ячейки Excel-а?
Гиперссылка представляет из себя URL на картинку на сайте (прилагаю для примера кусочек такого файла).
Кому-нибудь удалось получить URL гиперссылки из подобного файла?
(72) может уже не актуально, но нет, гиперссылка не загружается
(40) везде только и говорят про
но нигде не нашёл ни ссылку на документацию ни пример реализации . Может кто знает — поделитесь пожалуйста.
(73)Актуально!
Как бы научиться загружать гиперссылки?
(4) При загрузке Артикула = «80665» загружается как «80 665» вне зависимости от СпособЧтенияЗначенийТабличногоДокумента (Текст или Значение)
добрый день. На 64 битную подойдет?
(78) не проверял, но думаю должно работать
Перехожу на 1с розница 2.2. Хочу из EXEL импортировать. Не могу тут ничего скачать. на почту не перешлете.?
pushkarev.artem@mail.ru
Отправлю, только доберусь до компа
(80) отправлю, только доберусь до компа
Добрый день! Алексей, а эффективно ли будет работать построитель с такой шапкой:
(84) добрый день!
Я думаю, что построитель некорректно обработает такую шапку. Лучше чтобы шапка была в одну строку.
(85) спасибо за ответ и за статью!
Построитель положу в копилочку решений с простыми шапками, для этой попробую COM или ТабличныйДокумент =)
(86) рад что вам пригодилось )
Функция ПрочитатьЛистExcel(ТЗ = Неопределено, ЛистЭксель = Неопределено, НомерПервойСтроки = 1, НомерПервойКолонки = 1, ВсегоСтрок = 0, ВсегоКолонок = 0) Экспорт
Если ЛистЭксель = Неопределено Тогда
ЛистЭксель = ПолучитьCOMОбъект(,»Excel.Application»);
КонецЕсли;
Если ВсегоСтрок = 0 Тогда
ВсегоСтрок = ЛистЭксель.Cells.SpecialCells(11).Row;
КонецЕсли;
Если ВсегоКолонок = 0 Тогда
ВсегоКолонок = ЛистЭксель.Cells.SpecialCells(11).Column;
КонецЕсли;
Если ТЗ = Неопределено Тогда
ТЗ = Новый ТаблицаЗначений;
Для Счетчик = 1 По ВсегоКолонок Цикл
ТЗ.Колонки.Добавить(«Колонка»+Счетчик, Новый ОписаниеТипов(«Строка»));
КонецЦикла;
КонецЕсли;
Для Счетчик = НомерПервойСтроки По ВсегоСтрок Цикл
НоваяСтрока = ТЗ.Добавить();
КонецЦикла;
Область = ЛистЭксель.Range(ЛистЭксель.Cells(НомерПервойСтроки,НомерПервойКолонки), ЛистЭксель.Cells(ВсегоСтрок,ВсегоКолонок));
Данные = Область.Value.Выгрузить();
Для Счетчик = 0 По ВсегоКолонок-1 Цикл
ТЗ.ЗагрузитьКолонку(Данные[Счетчик], Счетчик);
КонецЦикла;
ЛистЭксель = Неопределено;
Возврат ТЗ;
КонецФункции
Используем этот механизм, спасибо. Но есть проблемы при загрузке файла с группировками (уровень группировки не определить) + в шапке не должно быть объединенных ячеек.
(89) да, некоторые ограничения есть
Вот пример файла, который данный способ не охватывает.
(91) да, этот файл метод 1с не сможет обработать корректно, первая строка должна содержать заголовки
Можно ли этим способом вытащить из файла только нужные колонки и сразу их сгруппировать? Далее нужно эти данные поместить во временную таблицу и соединять с регистрами. Для этого ТЗ должна быть типизированной. Как это сделать на уровне построителя?
(93) я думаю построитель автоматом не типизирует колонки, для запроса не получится подставить такую таблицу без спец. обработки