&НаКлиенте
Процедура <ИмяКоманды> (Команда)
Оповещение = Новый ОписаниеОповещения(«ЗагрузитьДанныеИзExcelВыбораФайла», ЭтотОбъект);
ПараметрыЗагрузки = ФайловаяСистемаКлиент.ПараметрыЗагрузкиФайла();
ПараметрыЗагрузки.ИдентификаторФормы = ЭтаФорма.УникальныйИдентификатор;
ПараметрыЗагрузки.Диалог.Заголовок = НСтр(«ru = ‘Выберите файл Excel для загрузки'»);
ПараметрыЗагрузки.Диалог.Фильтр = НСтр(«ru = ‘Файлы Excel (*.xlsx)|*.xlsx|Все файлы(*.*)|*.*'»);
ФайловаяСистемаКлиент.ЗагрузитьФайл(Оповещение, ПараметрыЗагрузки);
КонецПроцедуры
&НаКлиенте
Процедура ЗагрузитьДанныеИзExcelВыбораФайла(Результат, ДополнительныеПараметры) Экспорт
Если Результат = Неопределено Тогда
Возврат;
КонецЕсли;
СчитатьДанныеНаСервере(Результат);
КонецПроцедуры
&НаСервере
Процедура СчитатьДанныеНаСервере(ДанныеФайла)
ДвоичныеДанные = ПолучитьИЗВременногоХранилища(ДанныеФайла.Хранение);
Расширение = ОбщегоНазначенияКлиентСервер.РасширениеБезТочки(ОбщегоНазначенияКлиентСервер.ПолучитьРасширениеИмениФайла(ДанныеФайла.Имя));
ИмяВременногоФайла = ПолучитьИмяВременногоФайла(Расширение);
ДвоичныеДанные.Записать(ИмяВременногоФайла);
ТабличныйДокумент = Новый ТабличныйДокумент;
ТабличныйДокумент.Прочитать(ИмяВременногоФайла, СпособЧтенияЗначенийТабличногоДокумента.Текст); // либо значение
УдалитьФайлы(ИмяВременногоФайла);
Построитель = Новый ПостроительОтчета;
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТабличныйДокумент.Область(1, 1, ТабличныйДокумент.ВысотаТаблицы, ТабличныйДокумент.ШиринаТаблицы));
Построитель.Выполнить();
РезультатЧтения = Построитель.Результат.Выгрузить();
КонецПроцедуры
В статье рассмотрены варианты загрузки файлов Excel и табличных документов в объекты 1С, на примере таблиц значений. Если вам нужно загрузить файл Excel с одним или несколькими листами (не важно, xls или xlsx, или даже ods), или прочитать средствами 1С табличный документ mxl – читайте эту статью. Приводятся примеры кода, которые вы можете адаптировать под ваши задачи. Материал вышел большой, для удобства пользуйтесь навигацией по содержанию.
Содержание
Зачем писать свою загрузку? Ведь есть же типовые?
Во многих типовых конфигурациях на базе БСП имеется подсистема “Загрузка данных из файла”, кроме того, на ИТС можно найти обработку загрузки данных из табличного документа. Они позволяют загружать из внешних файлов данные во многие объекты: табличные части документов, справочники, регистры сведений. Кроме того, у этих обработок достаточно мощный функционал по сопоставлению данных из файла с объектами в базе 1С, разнообразные настройки, возможность создания элементов, в случае если они не найдены…
Так в чем же необходимость “изобретать велосипед”? На то несколько причин.
- Излишняя сложность. Ради универсальности приходится жертвовать простотой, и для рядового пользователя универсальные обработки могут оказаться сложнее, чем узкоспециализированная обработка, написанная под конкретный формат файла.
- Как ни странно, не стопроцентная универсальность. Действительно, как быть, если нам нужно загрузить не справочники, а планы видов характеристик? Или план расчета? Или на основании одного файла заполнить сразу несколько документов?
- Необходимость в специфичных алгоритмах. Например, при создании контрагента создавать также строго определенные договоры, или при загрузке в документ выполнять заполнение дополнительных, рассчетных колонок
- Сложные форматы исходных файлов. Например, исходный файл содержит несколько листов, и каждый из этих листов следует отдельно обработать. Второй пример – данные на листе сложно структурированы, и на одном листе могут содержаться несколько табличных частей, разделенных пустыми строками или колонками. Такие форматы встречаются, в частности, в отчетах зарубежных брокеров. На одном листе содержится информация и о сделках с финансовыми инструментами, и о движении денежных средств, и информация о ценных бумагах, и т.д.
В каком случае хороши универсальные загрузки из табличного документа?
Различные обработки загрузки из табличного документа отлично подходят, когда формат загружаемого файла не слишком сложный, а загрузка не предполагает множества дополнительных действий. Типичные примеры: загрузка прайс-листов, загрузка заказов, загрузка начальных остатков.
Подходящих случаев использования универсальных механизмов загрузки действительно много, иначе их не стали бы включать в библиотеку стандартных подсистем. Но если функциональности стандартных средств недостаточно, всегда можно создать свою собственную обработку. Ниже рассмотрены несколько приемов, которые можно использовать при загрузке файлов Excel и других табличных документов в 1С.
Особенности загрузки из файлов Excel с несколькими листами
При использовании метода табличного документа Прочитать(), файл Excel с несколькими листами читается так, что каждый лист помещается в отдельную именованную область ячеек, но при этом весь файл выводится в один табличный документ.
&НаКлиенте
Процедура ПрочитатьФайл(Команда)
ОбработкаОкончанияПомещения = Новый ОписаниеОповещения("ОбработчикОкончанияПомещения", ЭтотОбъект);
ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов;
ПараметрыДиалога.Фильтр = "Excel файлы(*.xls;*.xlsx)|*.xls;*.xlsx";
НачатьПомещениеФайлаНаСервер(ОбработкаОкончанияПомещения, , , АдресВХ, ПараметрыДиалога, ЭтотОбъект.УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ОбработчикОкончанияПомещения(ОписаниеПомещенногоФайла, ДополнительныеПараметры) Экспорт
АдресФайла = ОписаниеПомещенногоФайла.Адрес;
ПрочитатьИзВХНаСервере(АдресФайла);
КонецПроцедуры
&НаСервере
Процедура ПрочитатьИзВХНаСервере(АдресВХ)
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
ДД = ПолучитьИзВременногоХранилища(АдресВХ);
ДД.Записать(ИмяВременногоФайла);
СпособЧтения = СпособЧтенияЗначенийТабличногоДокумента.Текст;
//Рассмотрим пример, когда загружаем в 1С файл xlsx с листами
// Лист1, Лист2, Лист3, Лист4, Лист5
Попытка
ТабДок.Прочитать(ИмяВременногоФайла, СпособЧтения);
МассивИмен = Новый Массив;
Для Каждого Область Из ТабДок.Области Цикл
МассивИмен.Добавить(Область.Имя);
КонецЦикла;
Элементы.ИмяЛиста.СписокВыбора.ЗагрузитьЗначения(МассивИмен);
Исключение
КонецПопытки;
КонецПроцедуры
Загрузка с обходом строк и колонок
Для первого примера используем решение “в лоб”. Предположим, что количество и порядок колонок в файле известно заранее, и не меняется. Также будем считать постоянной и известной заранее первую строку, с которой следует начинать загрузку. Тогда нам достаточно в цикле пройти от первой строки до конца табличного документа.
Не следует путать методы табличного документа Область() и ПолучитьОбласть(). Первый возвращает область ячеек, а второй – новый табличный документ.
Если структура колонок таблицы, в которую мы загружаем, полностью идентична структуре колонок файла, мы можем загрузить данные, используя индексы.
&НаСервере
Процедура ПрочитатьВТаблицуЗначенийНаСервере()
//Работает и на сервере, и в тонком клиенте, возвращает область ячеек
ОбластьТЗ = ТабДок.Области.Лист2;
ОбластьТЗ = ТабДок.Область("Лист2");
//Работает только на сервере, возвращает табличный документ
Лист2 = ТабДок.ПолучитьОбласть("Лист2");
ТаблицаЗначений.Очистить();
ТЗ = ТаблицаЗначений.Выгрузить();
Для НомерСтроки = 6 По Лист2.ВысотаТаблицы Цикл
СтрТЗ = ТЗ.Добавить();
Для НомерКолонки = 2 По Лист2.ШиринаТаблицы Цикл
СтрТЗ[НомерКолонки-2] = Лист2.Область(НомерСтроки, НомерКолонки, НомерСтроки, НомерКолонки).Текст;
КонецЦикла;
КонецЦикла;
ТаблицаЗначений.Загрузить(ТЗ);
КонецПроцедуры
Если же состав колонок отличается, предпочтительнее использовать имена колонок. Обратите внимание, что при получении текста области, мы используем четыре параметра, чтобы получить область в виде конкретной ячейки. Но также можно указывать два параметра, если вы уверены, что в файле не будет объединенных ячеек, либо наоборот, указывать прямоугольную область объединенных ячеек – все зависит от конкретной задачи.
ТаблицаЗначений.Очистить();
ТЗ = ТаблицаЗначений.Выгрузить();
Для НомерСтроки = 6 По Лист2.ВысотаТаблицы Цикл
СтрТЗ = ТЗ.Добавить();
Наименование = Лист2.Область(НомерСтроки, 2, НомерСтроки, 2).Текст;
Количество = Лист2.Область(НомерСтроки, 3, НомерСтроки, 3).Текст;
Цена = Лист2.Область(НомерСтроки, 4, НомерСтроки, 4).Текст;
Сумма = Лист2.Область(НомерСтроки, 5, НомерСтроки, 5).Текст;
СтрТЗ.Наименование = Наименование;
СтрТЗ.Количество = Количество;
СтрТЗ.Цена = Цена;
СтрТЗ.Сумма = Сумма;
КонецЦикла;
ТаблицаЗначений.Загрузить(ТЗ);
С полученными данными можно дальше работать как угодно. Например, выполнить поиск товара по наименованию, и если он не найден – создать такой товар. Либо наоборот – вывести пользователю ошибку, что товар не удалось найти. Выбор подходящей бизнес-логики выходит за рамки данной статьи.
Загрузка табличного документа при помощи построителя отчета
В случае, когда у загружаемого файла есть строка с заголовками, можно выполнить загрузку из файла Excel, используя построитель отчета. В этом случае следует задать прямоугольную область ячеек, включая строку заголовков. В результате получится объект РезультатЗапроса, который далее можно обрабатывать как обычно – например, выгрузить в таблицу значений, поместить во временную таблицу и использовать в других запросах, и т.д.
&НаСервере
Процедура ПрочитатьПриПомощиПостроителяНаСервере()
Лист3 = ТабДок.ПолучитьОбласть("Лист3");
ОбластьЯчеек = Лист3.Область(5, 2, Лист3.ВысотаТаблицы, Лист3.ШиринаТаблицы);
ИсточникДанных = Новый ОписаниеИсточникаДанных(ОбластьЯчеек);
ПостроительОтчета = Новый ПостроительОтчета;
ПостроительОтчета.ИсточникДанных = ИсточникДанных;
ПостроительОтчета.Выполнить();
ТЗ = ПостроительОтчета.Результат.Выгрузить();
ТаблицаЗначений2.Загрузить(ТЗ);
КонецПроцедуры
Важно! В случае, если заголовки колонок в файле не соответствуют правилу именования переменных в 1С, они будут изменены компоновщиком – некорректные символы и пробелы будут заменены на знак подчеркивания “_”.
Динамическое сопоставление данных при загрузке
Предыдущие примеры ориентированы на работу с известным и неизменным составом колонок в исходном файле. Но что, если формат файла может меняться? Чтобы каждый раз не переписывать код, можно сделать его более гибким. Рассмотрим более сложный пример.
Предположим, есть несколько прайс-листов от разных поставщиков. Эти файлы имеют похожие, но не одинаковые форматы. Колонки могут располагаться в разном порядке, по-разному называться, шапка файла также имеет разное количество строк. В этом случае можно создать обработку, которая пусть и не будет универсальной, но будет достаточно гибко настраиваемой.
Добавим реквизит для указания имени области (чтобы можно было выбирать конкретный лист для чтения). Также добавим реквизит для указания пользователем номера первой строки. И основная часть настроек – таблица сопоставления колонок. Минимально достаточно будет сделать две колонки – номер исходный и номер принимающий. Такой прием распространен достаточно широко, и называется маппингом. Кроме маппинга по номерам существуют и другие варианты маппинга – например, по именам колонок.
&НаСервере
Процедура ПрочитатьСДинамическимиНастройкамиНаСервере()
НужныйЛист = ТабДок.ПолучитьОбласть(ИмяЛиста);
ТаблицаЗначений3.Очистить();
ТЗ = ТаблицаЗначений3.Выгрузить();
Для НомерСтроки = НомерПервойСтроки По НужныйЛист.ВысотаТаблицы Цикл
СтрТЗ = ТЗ.Добавить();
Для Каждого СтрСопоставления Из ТаблицаСопоставления Цикл
НомерКолонки = СтрСопоставления.НомерКолонкиИсходный;
СтрТЗ[СтрСопоставления.НомерКолонкиПринимающий-1] = НужныйЛист.Область(НомерСтроки, НомерКолонки, НомерСтроки, НомерКолонки).Текст;
КонецЦикла;
КонецЦикла;
ТаблицаЗначений3.Загрузить(ТЗ);
КонецПроцедуры
Более сложные сценарии
Не всегда форматы получаемых файлов удобны для загрузки. И не всегда есть возможность попросить передающую сторону обработать файл перед отправкой. Например, файл формируется каким-нибудь веб-ресурсом, либо присылается брокером по электронной почте. Можно конечно, посадить отдельного человека на обработку таких файлов и приведение их к единому формату – но это не самое рациональное и экономически оправданное решение.
Универсального “рецепта” нет, и далее будут только мои рекомендации и подходы, которые сформировались за годы практики.
Выше приведен специально усложненный формат файла, но на практике встречаются гораздо более неудобные файлы excel, которые нужно загрузить в 1С. Итак, с чем можно столкнуться, и что можно попробовать предпринять?
- “Плавающая” шапка. В зависимости от каких-нибудь условий, первая строка значимой информации может изменяться. Решение – динамически определять начало таблицы для загрузки – по тексту шапки таблицы, по цвету ячеек, и т.п.
- Несколько таблиц на одном листе. Решение – динамически определять начало и окончание каждой таблицы. В качестве окончания могут служить строки с текстом “Итого”, “Всего”. Также определять начало следующей таблицы и отнимать определенное количество строк, которое разделяет одну и другую таблицы в файле.
- Неподходящий формат ячеек. Текст “100 500.50” не является числом, и необходимо выполнить ряд действий, чтобы преобразовать его к числу – удалить разделитель разрядов, заменить точку на запятую, при необходимости удалить символ валюты, если он также присутствует в ячейке.
- Объединенные ячейки. Решение – анализируйте формат, используйте соответствующие параметры при задании области ячеек.
- Пустые строки, пустые колонки. Встречаются решения, когда файл анализируется с определенной строки и до первой встретившейся пустой ячейки – предполагается, что достигнут конец файла. Но такой подход не всегда корректен. Возможны случаи, когда после пустой строки или колонки продолжаются значимые строки. Решение – использовать более точный способ определения конца таблицы: метод ВысотаТаблицы, ячейки с ключевыми словами, ячейки с ключевым оформлением цветом.
Если вас не испугал последний раздел, и вы дочитали до конца – поздравляю и благодарю! Мне доводилось загружать файлы excel на китайском языке, загружать отчеты брокеров с самыми дикими форматами, загружать xls-файлы, полученные путем распознавания отсканированного изображения, и бороться с кучей ошибок.
Верьте в себя, не опускайте руки перед лицом проблем, и все получится!
vpivo 7 / 7 / 3 Регистрация: 09.01.2018 Сообщений: 210 |
||||
1 |
||||
Вывод в Эксель с посредством ТабличныйДокумент и ПостроительОтчета19.11.2018, 17:52. Показов 2078. Ответов 7 Метки нет (Все метки)
Добрый вечер. Какой-то ступор…
При выполнении пишет ошибку на строке *** «Несоответствие типов (Параметр № ‘1’)». Подскажите, что не так делаю?
0 |
Programming Эксперт 94731 / 64177 / 26122 Регистрация: 12.04.2006 Сообщений: 116,782 |
19.11.2018, 17:52 |
7 |
1824 / 1243 / 444 Регистрация: 16.01.2015 Сообщений: 5,449 |
|
19.11.2018, 19:47 |
2 |
vpivo, ТаблицаОтчета (табличный документ) и ТаблицаЗначений как в примере — это как картинка и коза. При большом желании можно найти что-то общее, но реально — абсолютно разные сущности
0 |
vpivo 7 / 7 / 3 Регистрация: 09.01.2018 Сообщений: 210 |
||||
19.11.2018, 23:33 [ТС] |
3 |
|||
Кто Вам такое сказал? ТаблицаОтчета — реквизит основной формы типа ТаблицаЗначений, с 8-ю колонками типа строка, ограниченная по длине, и число. Сам код в процедуре &НаСервере. Добавлено через 3 часа 20 минут
0 |
1824 / 1243 / 444 Регистрация: 16.01.2015 Сообщений: 5,449 |
|
19.11.2018, 23:37 |
4 |
vpivo, И все-таки дело было в «ТаблицаОтчета» — не таблица значений
0 |
7 / 7 / 3 Регистрация: 09.01.2018 Сообщений: 210 |
|
20.11.2018, 00:00 [ТС] |
5 |
Все получилось, в файл выгружается,но… Эксель его открывает с предупреждением, что формат файла не соответствует его расширению. Но все-таки открывает и работать можно. Добавлено через 2 минуты
0 |
1824 / 1243 / 444 Регистрация: 16.01.2015 Сообщений: 5,449 |
|
20.11.2018, 00:06 |
6 |
vpivo, XLSX своеобразный формат. Это xml упакованный zip. Сохраняйте в xls
С какого перепуга тогда Конструктор пишет, что это ТаблицаЗначений? Где пишет? Скрин покажите, чтобы понять о чем вы
0 |
7 / 7 / 3 Регистрация: 09.01.2018 Сообщений: 210 |
|
20.11.2018, 07:46 [ТС] |
7 |
На слово не верите? Полюбуйтесь в файлах.
0 |
Phil 434 / 305 / 92 Регистрация: 28.05.2014 Сообщений: 1,247 |
||||
20.11.2018, 08:45 |
8 |
|||
vpivo, &НаСервере
Миниатюры
1 |
23.04.2019
Получение таблицы значений из excel в 1С v8, без COM, внешних источников данных и т.д.
EXCELВТаблицуЗначений() — За 10 строчек кода!
Реализация протестирована на 1С 8.3.12.1714 (x64).
WARNING
Данная статья не претендует на оригинальность и не является конечным решением.
Подходы решения задач и примеры программного кода несут исключительно обучающий характер.
Существует масса подходов загрузки данных из EXCEL в 1С. Большинство решений основаны на COM или еще более сложных возможностях платформы.
Для себя разработал наиболее оптимальный вариант:
EXCEL -> Табличный документ -> Построитель запроса -> Таблица значений
Итак, приступим:
- Прочитать Excel файл на клиенте, для передачи на сервер:
&НаКлиенте Процедура ЗагрузитьEXCEL(Команда) Файл = Новый Файл(ПутьКEXCEL); Если НЕ Файл.Существует() Тогда Возврат; КонецЕсли; ДвоичныеДанные = Новый ДвоичныеДанные(ПутьКEXCEL); ДокументРезультат = EXCELВТаблицуЗначений(ДвоичныеДанные, Файл.Расширение); ДокументРезультат.Показать(); КонецПроцедуры
- Выполнить чтение Excel в таблицу значений:
&НаСервере Функция EXCELВТаблицуЗначений(ДвоичныеДанные, Расширение) ФайлEXCELНаСервере = ПолучитьИмяВременногоФайла(Расширение); ДвоичныеДанные.Записать(ФайлEXCELНаСервере); ТабличныйДокумент = Новый ТабличныйДокумент; ТабличныйДокумент.Прочитать(ФайлEXCELНаСервере); УдалитьФайлы(ФайлEXCELНаСервере); ОбластьТаблицы = ТабличныйДокумент.Область(8, 1, ТабличныйДокумент.ВысотаТаблицы, ТабличныйДокумент.ШиринаТаблицы); ПостроительЗапроса = Новый ПостроительЗапроса; ПостроительЗапроса.ИсточникДанных = Новый ОписаниеИсточникаДанных(ОбластьТаблицы); ПостроительЗапроса.Выполнить(); ТаблицаДанных = ПостроительЗапроса.Результат.Выгрузить(); // теперь поссмторим что в Таблице Возврат ТаблицаЗначенийВТабличныйДокумент(ТаблицаДанных); КонецФункции
-
Визуализировать таблицу значений:
&НаСервереБезКонтекста Функция ТаблицаЗначенийВТабличныйДокумент(ТаблицаДанных) ПостроительОтчета = Новый ПостроительОтчета; ПостроительОтчета.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТаблицаДанных); ДокументРезультат = Новый ТабличныйДокумент; Построительотчета.Вывести(ДокументРезультат); Возврат ДокументРезультат; КонецФункции
Описание преобразования данных:
- Получаем исходный файл на клиенте;
- На основании файла создаем двоичные данные и получаем расширение файла;
- Передаем двоичные данные на сервер;
- Создаем дубль файла excel на сервере;
- Читаем файл в новый табличный документ;
- Получаем область табличного документа, где находятся полезные данные (ТабличныйДокумент.Область(8, 1, ТабличныйДокумент.ВысотаТаблицы, ТабличныйДокумент.ШиринаТаблицы));
- Создаем новый построитель запроса и установим в качестве источника данных — область полезных данных;
- Выполним построитель и получим результат запроса;
- Результат запроса выгрузим в таблицу значений.
Плюсы реализации:
- Скорость работы по сравнению с COM EXCEL
- Возможно выполнять загрузку где EXCEL нет вообще (MAC | LINUX | etc…)
- Простота реализации