Приемы эффективной загрузки данных из Excel в 1С

Показаны приемы эффективной работы с Excel для загрузки данных в 1С.

В публикации показаны приемы по загрузке данных из файла Excel в таблицу значений..

Протестировано на версии платформы 1С:Предприятие 8.3 (8.3.9.1818).

В версии 8.3 для загрузки из Excel существует альтернатива COM объекту. У табличного документа есть метод Прочитать.

Особенно актуально для файлов больших объемов, т.к. табличный документ обрабатывается гораздо быстрее.

А табличный документ легко трансформируется в таблицу значений через построитель запроса.

Во вложении обработка — пример загрузки и вывода в табличный документ и таблицу значений.

Рабочий код занимает несколько строк:

//Вывод в табличный документ

ТабличныйДокумент = Новый ТабличныйДокумент;

ТабличныйДокумент.Прочитать(Файл, СпособЧтенияЗначенийТабличногоДокумента.Значение);

//вывод в таблицу значений

ПЗ = Новый ПостроительЗапроса;

ПЗ.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТабличныйДокумент.Область());

ПЗ.ДобавлениеПредставлений = ТипДобавленияПредставлений.НеДобавлять;

ПЗ.ЗаполнитьНастройки();

ПЗ.Выполнить();

ТаблицаЗначений = ПЗ.Результат.Выгрузить();

P.S. При выводе в таблицу значений через построитель запроса, названия колонок в источнике данных должны быть первой строкой, иначе построитель не сможет получить и преобразовать их в колонки таблицы значений и выдаст ошибку.

Во внешней обработке демонстрация загрузки.

75 Comments

  1. BigB

    Как воспримет построитель вот такие найменования колонок например:

    Наименование товара

    Кол-во

    Дата документа

    Reply
  2. alexey.kutya

    (1) воспримет нормально, но переименует по-своему ))

    вот так

    НаименованиеТовара

    Кол_во

    ДатаДокумента

    Reply
  3. MaxS

    Допустим требуется заполнить реквизит Артикул справочника номенклатура. Исходный файл содержит соответствующую колонку с текстом «000123», «000124» и т.п. все символы цифровые. Какое значение попадёт в строковый реквизит номенклатуры?

    Если «123», «124» и т.п., то приемы эффективной загрузки данных из Excel в 1С разбиваются о реальность ))

    Reply
  4. alexey.kutya

    Попадет значение «000123».

    Reply
  5. alexey.kutya

    (3) Попадет значение «000123».

    Reply
  6. maxopik2

    У меня проблема в методе «Прочитать()» , ядро 8.3.10.2580 : при загрузке больших файлов (2-3 Mb) расход памяти сервера может достигать 12 Gb

    пришлось отказаться от этого метода и пользоваться ADODB

    Reply
  7. MaxS

    (4) Спасибо за эксперимент, пересмотрю своё мнение об этом методе. Мои опыты приводили к потере лидирующих нулей.

    Reply
  8. alexey.kutya

    (7) возможно что-то уже изменили в платформе

    и еще есть один нюанс. У метода Прочитать есть второй параметр СпособЧтенияЗначений.

    <СпособЧтенияЗначений> (необязательный)

    Тип: СпособЧтенияЗначенийТабличногоДокумента.

    Определяет, каким образом нужно интерпретировать значения, считываемые из исходного документа XLS, XLSX или ODS.

    При загрузке табличного документа из формата Excel 97 — 2010 и OpenOffice Calc, в случае если в ячейке исходного документа содержалось значение типа Дата или Число, то в ячейку результирующего табличного документа это значение попадает в зависимости от значения этого параметра.

    Значение по умолчанию: Текст.

    Reply
  9. alexey.kutya

    (6) обидно )) но что поделаешь

    Reply
  10. Alligator84

    Спасибо, познавательно!

    Reply
  11. maxopik2

    (9) Не обидно, а вопрос: Это ошибка платформы (т.к. не может из файла 2 Mb появиться файл mxl объемом 11Gb) или я что-то не так делаю?

    Reply
  12. alexey.kutya

    (11) да интересно ) если хотите, отправьте мне этот файл. Я попробую его загрузить. Если конечно там нет конфиденциальной информации.

    Reply
  13. MaxS

    (11) А если на этом же сервере запустить тонкий клиент и через «Файл — Открыть» открыть этот файл? Расход памяти такой же будет?

    Reply
  14. Lapitskiy

    а зачем построитель?

    Можно по циклу обойти Табличный документ.

    Reply
  15. VmvLer

    табличные документы 1С много «весят» — это особенно ощутимо для больших данных.

    покрутите предлагаемый метод для эксель-файлов с сотнями тысяч строк, интересно за какое время вы прочтете

    Reply
  16. alexey.kutya

    (14) можно и циклом. Это альтернативный способ. Мне больше нравится через построитель.

    Reply
  17. alexey.kutya

    (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

    Reply
  18. vladismi

    Забавно. Попробуем.

    Reply
  19. maxopik2

    (12) Вот файл

    Reply
  20. maxopik2

    (13) Попробовал через тонкий клиент. Расход памяти такой же.

    Reply
  21. qwinter

    Кто то узнал о существовании построителя. Круто.

    Reply
  22. Lapitskiy

    (16) я думаю, из-за построителя и расход памяти поболее будет.

    Reply
  23. alexey.kutya

    (23) сам не замерял, но вполне возможно )

    Reply
  24. alexey.kutya

    (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

    Reply
  25. PavelKolobkov

    Здесь обсуждалось подобное сабжу

    Reply
  26. alexey.kutya

    (26) там немного про другое, но в комментариях да, упоминается про метод Прочитать.

    Reply
  27. logarifm

    А где приемы? Я насчитал только один! Отчитали и накрыли построителем, а остальные ?

    Reply
  28. alexey.kutya

    (28) ну вот и получается загрузка в 2 приема ))

    Рассмотреть все возможные варианты работы с Excel не являлось целью публикации. Я просто хотел показать как можно с наменьшими затратами, используя код в несколько строк выполнить задачу.

    Reply
  29. Infector

    Был небольшой опыт:

    Когда попытался обработать через «прочитать» сохраненную контрагентом печатную форму с графическими объектами, все это дело просто повесилось. Пока что ADO и COM-объекты в таких случаях надежнее.

    Reply
  30. AzagTot

    Спасибо! Очень интересный способ.

    Насколько я понял, он не требует наличия на компьютере Microsoft Excel или OpenOffice Calc для чтения соответствующих таблиц?

    Метод Табличного Документа «Записать» точно не требует, проверено)

    Reply
  31. alexey.kutya

    (30) да, в таком случае лучше ADO.

    Reply
  32. alexey.kutya

    Я не проверял, но думаю должен работать.

    Reply
  33. alexey.kutya

    (31) Я не проверял, но думаю должен работать.

    Reply
  34. wolfsoft

    (22) Ага, ещё бы при чтении некоторых эксель-файлов не вылетало с ошибкой и страницы бы читала.

    Reply
  35. kredko

    Хороший метод, только вот не работает с файлами эксель с расширением xlm, который с макросами. И Данные с нескольких страниц помещает в один табличный документ.

    Reply
  36. Stradivari

    Спасибо. Статья помогла!

    Reply
  37. echo77

    Просто и полезно. Укажите в публикации, пожалуйста, что это работает начиная с платформы версии 8.3.6, а с версии 8.3.10 можно грузить данные с определенного листа. Можно так же подкрепить ссылка на ИТС

    Reply
  38. d4rkmesa

    Гениально. Не знал про такие фокусы с построителем и табличным документом.

    Reply
  39. triviumfan

    (41) Тоже не знал) До сих пор ADO/EXCEL юзаю =)

    Reply
  40. YuriIn

    (31) на сколько мне известно в 1С есть встроенный механизм работы с табличными документами, и в данном случае работает как раз встроенный механизм и получается приложение необязательное.

    Reply
  41. alexey.kutya

    (44) Спасибо за дополнение 🙂 У вас отлично реализовано. Думаю будет очень полезно.

    Reply
  42. ediks

    (44) А что за объект КэшФункции в функции ТекстОбластиЛиста?

    И в строке Ф = НовыйФайл(ФайлExcel); пробел не пропущен НовыйФайл?

    Reply
  43. ImHunter

    (46) Да, точно

    Тут же в модуле

    // Функция — Новый файл
    // Создает или переиспользует объект Файл. Для сокращения кол-ва кода. Заодно можно делать проверку существования файла.
    // Параметры:
    //  Файл      — Файл, Строка  — Если передается объект Файл, то он же и возвращается.
    // Если передается Строка (путь), то создается Файл по переданному пути
    //  ПроверятьСуществование  — Булево — Проверять ли существование файла. Если не существует, то идет вызов исключения.
    //
    // Возвращаемое значение:
    //  Файл — Созданный или переиспользованный файл
    //
    Функция НовыйФайл(Файл, ПроверятьСуществование = Истина)
    
    ТипЗнчФайл = ТипЗнч(Файл);
    Результат = Неопределено;
    Если ТипЗнчФайл=КэшФункции.ТипФайл() Тогда
    Результат = Файл;
    ИначеЕсли ТипЗнчФайл=КэшФункции.ТипСтрока() Тогда
    Результат = Новый Файл(Файл);
    Иначе
    ВызватьИсключение(«Непредусмотренный тип параметра Файл » + ТипЗнчФайл);
    КонецЕсли;
    
    Если ПроверятьСуществование=Истина И Не Результат.Существует() Тогда
    ВызватьИсключение(«Файл не существует»);
    КонецЕсли;
    
    Возврат Результат;
    
    КонецФункции
    

    Показать

    А КэшФункции — это модуль, закешированный на сеанс. Там, в том числе, закешированы типы данных:

    Функция ТипСтрока() Экспорт
    Возврат Тип(«Строка»);
    КонецФункции
    
    Функция ТипДата() Экспорт
    Возврат Тип(«Дата»);
    КонецФункции
    
    Функция ТипФайл() Экспорт
    Возврат Тип(«Файл»);
    КонецФункции
    
    Функция ТипСтруктура() Экспорт
    Возврат Тип(«Структура»);
    КонецФункции
    
    Функция ТипНеопределено() Экспорт
    Возврат Тип(«Неопределено»);
    КонецФункции
    
    Функция ТипУникальныйИдентификатор() Экспорт
    Возврат Тип(«УникальныйИдентификатор»);
    КонецФункции
    
    Функция ТипЭлементСпискаЗначений() Экспорт
    Возврат Тип(«ЭлементСпискаЗначений»);
    КонецФункции
    
    Функция ТипСписокЗначений() Экспорт
    Возврат Тип(«СписокЗначений»);
    КонецФункции
    
    Функция ТипТабличныйДокумент() Экспорт
    Возврат Тип(«ТабличныйДокумент»);
    КонецФункции
    
    Функция ТипМассив() Экспорт
    Возврат Тип(«Массив»);
    КонецФункции
    

    Показать

    Reply
  44. ImHunter

    На основании публикации доработал и свой модуль. Теперь выгружаю и в ТЗ.

    // Функция — Получить таблицу значений excel
    //
    // Параметры:
    //  Лист — ЭлементСпискаЗначений, ТабличныйДокумент  — Где искать текст.
    //  ПоляТолькоПоДокументу  — Булево — Если Истина, то создаются поля по верхней строке ТабДока. Если Ложь, то создаются авто-поля Поле[N] по всей ширине ТабДока.
    //
    // Возвращаемое значение:
    //  ТаблицаЗначений — ТЗ с данными ТабДока
    //
    Функция ПолучитьТаблицуЗначенийExcel(Лист, ПоляТолькоПоДокументу = Ложь) Экспорт
    
    Если Истина Тогда
    ТабДок = ПолучитьТабДок(Лист);
    Иначе
    ТабДок = Новый ТабличныйДокумент;
    КонецЕсли;
    
    Если ТабДок.ВысотаТаблицы=0 Тогда
    Возврат Неопределено;
    КонецЕсли;
    
    // вставим заголовки
    Если ПоляТолькоПоДокументу=Ложь Тогда
    ВерхняяСтрока = ТабДок.Область(«R1»);
    ТабДок.ВставитьОбласть(ВерхняяСтрока, ВерхняяСтрока, ТипСмещенияТабличногоДокумента.ПоВертикали, Ложь);
    ВерхняяСтрока = ТабДок.Область(«R1»);
    ВерхняяСтрока.Очистить();
    Для Кол=1 По ТабДок.ШиринаТаблицы Цикл
    ТабДок.Область(1, Кол).Текст = «Поле» + Формат(Кол, «ЧГ=»);
    КонецЦикла;
    КонецЕсли;
    
    ПЗ = Новый ПостроительЗапроса;
    ПЗ.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТабДок.Область());
    ПЗ.ДобавлениеПредставлений = ТипДобавленияПредставлений.НеДобавлять;
    ПЗ.ЗаполнитьНастройки();
    ПЗ.Выполнить();
    ТаблицаЗначений = ПЗ.Результат.Выгрузить();
    
    // вставим заголовки
    Если ПоляТолькоПоДокументу=Ложь Тогда
    ВерхняяСтрока = ТабДок.Область(«R1»);
    ТабДок.УдалитьОбласть(ВерхняяСтрока, ТипСмещенияТабличногоДокумента.ПоВертикали);
    КонецЕсли;
    
    Возврат ТаблицаЗначений;
    
    КонецФункции
    
    Функция ПолучитьТабДок(Лист)
    
    ТипЗнчЛист = ТипЗнч(Лист);
    Если ТипЗнчЛист=КэшФункции.ТипТабличныйДокумент() Тогда
    ТабДок = Лист;
    ИначеЕсли ТипЗнчЛист=КэшФункции.ТипЭлементСпискаЗначений() Тогда
    ТабДок = Лист.Значение;
    Иначе
    ВызватьИсключение(«Неподдерживаемый тип параметра Лист » + ТипЗнчЛист);
    КонецЕсли;
    
    Возврат ТабДок;
    
    КонецФункции
    

    Показать

    Reply
  45. vpaoli

    (45) Я недавно сравнивал скорость загрузки через ADO и с помощью метода

    Область = ЛистЭксель.Range(…);

    Данные = Область.Value.Выгрузить();

    Получилось, что второй метод быстрее ADO где то на 25%

    Вы не сравнивали метод Range с вашим методом загрузки ? Что быстрее и насколько. Может сравните для полноты ощущений …?

    Reply
  46. vpaoli

    Раз уж Вы пишете «Приемы эффективной загрузки …» , наверно необходимо сравнение с другими существующими . Иначе это может быть и «не эффективной загрузки».

    Есть метод:

    Область = ЛистЭксель.Range(…);
    Данные = Область.Value.Выгрузить(); 

    Вы не сравнивали метод Range с вашим методом загрузки ? Что быстрее и насколько ?

    Reply
  47. alexey.kutya

    (59)

    Область = ЛистЭксель.Range(…);

    Данные = Область.Value.Выгрузить();

    Попробовал на 1 млн. строк.

    Время выполнения чтения файла вашим методом 36 сек. Время выполнения методом описанным в моей публикации 193 сек. Разница в 5 раз 🙂 Но ваш метод возвращает массивы значений, надо попробовать их разобрать.

    Reply
  48. ImHunter

    (65) Так ожидаемо, что ТабДоком медленнее. И значительно тяжелее, наверное, по расходу памяти.

    Но профит в том, что не нужен Excel, ADO-провайдеры. Пожалуй, только из-за этого на табдоки перебрался.

    Reply
  49. alexey.kutya

    (66)

    ADO-провайдер

    Конечно, если время выполнения приемлемое, то почему бы и нет.

    Reply
  50. vpaoli

    (65)

    Но ваш метод возвращает массивы значений, надо попробовать их разобрать.

    Все уже разобрано…. Есть публикации вместе с кодом на инфостарте.

    Reply
  51. ImHunter

    Хех, недолго радовался:( Придется отказаться от такого чтения. Тесты в боевых условиях валятся по нехватке памяти. Похоже, чтение ТабДоком сильно не любит формулы.

    Reply
  52. alexey.kutya

    (69) Да, жаль )

    Reply
  53. ImHunter

    (70) Для справки. Тесты гонял на 8.3.10.2580, 32-бит.

    Так что, народ, аккуратнее с загрузкой ТабДоком…

    Reply
  54. vis_tmp

    Не могу понять, вашим методом загружается ли гиперссылка из ячейки Excel-а?

    Гиперссылка представляет из себя URL на картинку на сайте (прилагаю для примера кусочек такого файла).

    Кому-нибудь удалось получить URL гиперссылки из подобного файла?

    Reply
  55. alexey.kutya

    (72) может уже не актуально, но нет, гиперссылка не загружается

    Reply
  56. user755058

    (40) везде только и говорят про

    а с версии 8.3.10 можно грузить данные с определенного листа

    но нигде не нашёл ни ссылку на документацию ни пример реализации . Может кто знает — поделитесь пожалуйста.

    Reply
  57. vis_tmp

    (73)Актуально!

    Как бы научиться загружать гиперссылки?

    Reply
  58. user700035_6550355

    (4) При загрузке Артикула = «80665» загружается как «80 665» вне зависимости от СпособЧтенияЗначенийТабличногоДокумента (Текст или Значение)

    Reply
  59. pushkarev

    добрый день. На 64 битную подойдет?

    Reply
  60. alexey.kutya

    (78) не проверял, но думаю должно работать

    Reply
  61. pushkarev

    Перехожу на 1с розница 2.2. Хочу из EXEL импортировать. Не могу тут ничего скачать. на почту не перешлете.?

    Reply
  62. pushkarev
  63. alexey.kutya

    Отправлю, только доберусь до компа

    Reply
  64. alexey.kutya

    (80) отправлю, только доберусь до компа

    Reply
  65. user811769

    Добрый день! Алексей, а эффективно ли будет работать построитель с такой шапкой:

    Reply
  66. alexey.kutya

    (84) добрый день!

    Я думаю, что построитель некорректно обработает такую шапку. Лучше чтобы шапка была в одну строку.

    Reply
  67. user811769

    (85) спасибо за ответ и за статью!

    Построитель положу в копилочку решений с простыми шапками, для этой попробую COM или ТабличныйДокумент =)

    Reply
  68. alexey.kutya

    (86) рад что вам пригодилось )

    Reply
  69. user703966_martynyuknatalia

    Функция ПрочитатьЛист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 Цикл

    ТЗ.ЗагрузитьКолонку(Данные[Счетчик], Счетчик);

    КонецЦикла;

    ЛистЭксель = Неопределено;

    Возврат ТЗ;

    КонецФункции

    Reply
  70. medangel

    Используем этот механизм, спасибо. Но есть проблемы при загрузке файла с группировками (уровень группировки не определить) + в шапке не должно быть объединенных ячеек.

    Reply
  71. alexey.kutya

    (89) да, некоторые ограничения есть

    Reply
  72. user892257

    Вот пример файла, который данный способ не охватывает.

    Reply
  73. alexey.kutya

    (91) да, этот файл метод 1с не сможет обработать корректно, первая строка должна содержать заголовки

    Reply
  74. user1315758

    Можно ли этим способом вытащить из файла только нужные колонки и сразу их сгруппировать? Далее нужно эти данные поместить во временную таблицу и соединять с регистрами. Для этого ТЗ должна быть типизированной. Как это сделать на уровне построителя?

    Reply
  75. alexey.kutya

    (93) я думаю построитель автоматом не типизирует колонки, для запроса не получится подставить такую таблицу без спец. обработки

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *