Приемы эффективной загрузки данных из 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 не будет опубликован. Обязательные поля помечены *