Выгрузка в Excel из кода 1С: табличный документ, COM и CSV
Содержание
Чтобы программно выгрузить данные из 1С в Excel, соберите их в ТабличныйДокумент и вызовите ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX). Excel на компьютере для этого не нужен, код работает и на сервере, и в клиенте. COM-соединение с Excel.Application нужно, только когда в файле должны быть формулы, макросы или готовый шаблон заказчика.
Типичная боль — выгрузка, которая на тестовых 200 строках работала за секунду, а на реальных 50 000 висит полчаса или оставляет в диспетчере задач десяток процессов EXCEL.EXE. Решение — выбрать способ под задачу и не дёргать Excel по ячейке. Всё относится к платформе 8.3 и не зависит от конфигурации: БП, ЗУП и УТ здесь ведут себя одинаково.
Три способа выгрузить данные из 1С в Excel программно
Выбор способа определяет, где будет работать код и сколько он проживёт без поддержки.
| Способ | Нужен Excel | Где работает | Когда выбирать |
|---|---|---|---|
ТабличныйДокумент.Записать в XLSX | нет | сервер, тонкий и веб-клиент | 90% задач: отчёты, реестры, выгрузки по расписанию |
COM-объект Excel.Application | да | только Windows-клиент с установленным Excel | формулы, сводные таблицы, заполнение чужого шаблона |
CSV через ЗаписьТекста | нет | везде | сотни тысяч строк без оформления |
Порядок решения простой:
- 📄 Нужен файл с данными и оформлением — табличный документ.
- 🧮 Нужны живые формулы, автофильтр, группировки Excel — COM.
- 🚚 Нужен «сырой» массив для загрузки в другую систему — CSV.
Если выгрузку будут вызывать регламентным заданием или из веб-клиента, COM сразу отпадает. Не стоит начинать с него «потому что так привычнее».
Запись табличного документа в формат XLSX
Это основной способ. Данные получаете запросом, выводите в табличный документ и сохраняете. Пример ниже выгружает любую таблицу значений: первая строка — имена колонок, числа уходят в Excel числами, а не текстом.
&НаСервере
Функция ТаблицаВТабличныйДокумент(ТаблицаДанных)
ТабДок = Новый ТабличныйДокумент;
ОписаниеЧисла = Новый ОписаниеТипов("Число");
НомерКолонки = 0;
Для Каждого Колонка Из ТаблицаДанных.Колонки Цикл
НомерКолонки = НомерКолонки + 1;
Область = ТабДок.Область(1, НомерКолонки);
Область.Текст = Колонка.Имя;
Область.Шрифт = Новый Шрифт(, , , Истина);
КонецЦикла;
НомерСтроки = 1;
Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
НомерСтроки = НомерСтроки + 1;
НомерКолонки = 0;
Для Каждого Колонка Из ТаблицаДанных.Колонки Цикл
НомерКолонки = НомерКолонки + 1;
Значение = СтрокаДанных[Колонка.Имя];
Область = ТабДок.Область(НомерСтроки, НомерКолонки);
Если ТипЗнч(Значение) = Тип("Число") Тогда
Область.СодержитЗначение = Истина;
Область.ТипЗначения = ОписаниеЧисла;
Область.Значение = Значение;
Иначе
Область.Текст = Строка(Значение);
КонецЕсли;
КонецЦикла;
КонецЦикла;
Возврат ТабДок;
КонецФункции
Дальше документ записывают во временный файл и отдают пользователю через временное хранилище:
&НаСервере
Функция ВыгрузитьНаСервере()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Код КАК Код,
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ЭтоГруппа";
ТабДок = ТаблицаВТабличныйДокумент(Запрос.Выполнить().Выгрузить());
ИмяФайла = ПолучитьИмяВременногоФайла("xlsx");
ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX);
Адрес = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ИмяФайла), УникальныйИдентификатор);
УдалитьФайлы(ИмяФайла);
Возврат Адрес;
КонецФункции
Код выше пишется в модуле формы обработки: УникальныйИдентификатор — свойство формы. В общем модуле передайте его параметром.
Если выгрузка уже есть в виде отчёта на СКД, руками строить ничего не нужно. Результат компоновки выводится в табличный документ стандартной связкой КомпоновщикМакетаКомпоновкиДанных → ПроцессорКомпоновкиДанных → ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент, а дальше тот же Записать.
Кроме XLSX, метод Записать умеет ТипФайлаТабличногоДокумента.XLS (старый формат Excel 97–2003), MXL, PDF, HTML, ODS. Старый XLS выбирайте, только если получатель работает в программе, которая не открывает XLSX.
Excel через COM-соединение: управление книгой из кода 1С
COM-объект запускает настоящий Excel и даёт управлять им как из VBA: листы, ячейки, формулы, сохранение. Работает только в клиенте под Windows, где установлен Microsoft Excel. Данные удобнее подготовить на сервере, а на клиент передать массивом структур.
&НаКлиенте
Процедура ВыгрузитьЧерезExcel(Команда)
Данные = ПолучитьДанныеНаСервере(); // массив структур Наименование, Количество
Excel = Неопределено;
Попытка
Excel = Новый COMОбъект("Excel.Application");
Excel.DisplayAlerts = Ложь;
Excel.ScreenUpdating = Ложь;
Книга = Excel.Workbooks.Add();
Лист = Книга.Worksheets(1);
Лист.Cells(1, 1).Value = "Номенклатура";
Лист.Cells(1, 2).Value = "Количество";
НомерСтроки = 1;
Для Каждого Элемент Из Данные Цикл
НомерСтроки = НомерСтроки + 1;
Лист.Cells(НомерСтроки, 1).Value = Элемент.Наименование;
Лист.Cells(НомерСтроки, 2).Value = Элемент.Количество;
КонецЦикла;
Лист.Cells(НомерСтроки + 1, 2).Formula = "=SUM(B2:B" + Формат(НомерСтроки, "ЧГ=0") + ")";
Лист.Columns("A:B").AutoFit();
Книга.SaveAs("C:\Выгрузка\Остатки.xlsx", 51);
Книга.Close(Ложь);
Исключение
Сообщить("Ошибка выгрузки в Excel: " + ОписаниеОшибки());
КонецПопытки;
Если Excel <> Неопределено Тогда
Excel.Quit();
Excel = Неопределено;
КонецЕсли;
КонецПроцедуры
Что здесь важно:
DisplayAlerts = Ложь— Excel не покажет скрытый вопрос «Заменить файл?», из-за которого код повисает навсегда.- Второй параметр
SaveAs— формат файла:51это XLSX без макросов,56— старый XLS. - В свойство
Formulaформулу пишут с английскими именами функций (SUM,IF). Для русских (СУММ) естьFormulaLocal, но он зависит от языка Office у пользователя. Формат(НомерСтроки, "ЧГ=0")убирает пробел-разделитель тысяч. Без него на строке 1 000 формула превратится в=SUM(B2:B1 000)и упадёт.
Запускать Excel через COM на сервере 1С Microsoft не поддерживает: у служебной учётной записи нет профиля Office, Excel зависает на диалогах, процессы копятся. Для сервера и регламентных заданий — только табличный документ или CSV.
Шаблоны и форматирование ячеек при выгрузке
Шаблон избавляет от десятков строк кода «жирный, рамка, ширина колонки». Есть два варианта.
Макет табличного документа в конфигурации
В обработке создаёте макет типа «Табличный документ», размечаете именованные области (Шапка, Строка, Подвал) и параметры в ячейках. Код выводит области по очереди:
Макет = ПолучитьМакет("Реестр");
ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
ТабДок = Новый ТабличныйДокумент;
ОбластьШапка.Параметры.Период = Формат(ТекущаяДата(), "ДЛФ=D");
ТабДок.Вывести(ОбластьШапка);
Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
ОбластьСтрока.Параметры.Заполнить(СтрокаДанных);
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
Шрифты, рамки, заливка, ширина колонок и объединения ячеек из макета переходят в XLSX. Формат числа задаётся в свойствах ячейки макета, например ЧДЦ=2 — два знака после запятой.
Если в Excel суммы пришли текстом и не складываются, у ячейки макета включите «Содержит значение» и укажите тип «Число». Без этого параметр выводится строкой.
Готовая книга Excel как шаблон
Когда бланк прислал заказчик и менять его нельзя, храните файл .xlsx в макете типа «Двоичные данные». Перед выгрузкой запишите его во временный файл (ПолучитьМакет("Бланк").Записать(ИмяВременногоФайла)), откройте через COM Excel.Workbooks.Open(ИмяВременногоФайла) и заполняйте ячейки.
💡 Приём практика: в шаблоне задайте ячейкам имена (Ctrl+F3 в Excel), а в коде пишите Лист.Range("ИтогоКОплате").Value = Сумма. Заказчик сдвинет строки — код не сломается.
Коды с ведущими нулями
ИНН, коды номенклатуры 00012, номера счетов Excel превращает в числа и теряет нули. В COM задайте колонке текстовый формат до записи: Лист.Columns("A").NumberFormat = "@". В табличном документе выводите такие значения через Текст — они придут строкой.
Большие объёмы: как ускорить программную выгрузку в Excel
Основные тормоза — не сам Excel, а лишние обращения к базе и к COM.
Запрос
- 🔍 Выбирайте в запросе только нужные колонки и сразу представления:
Номенклатура.Наименование,ПРЕДСТАВЛЕНИЕ(Контрагент). ВызовСтрока(Ссылка)в цикле делает отдельное обращение к базе на каждую строку. - 📦 Не обходите объекты через
Справочники.Х.Выбрать()сПолучитьОбъект(): для выгрузки нужны данные, а не объекты.
COM
Каждое Лист.Cells(Строка, Колонка).Value = … — межпроцессный вызов. На 50 000 строк × 10 колонок это полмиллиона вызовов, выгрузка растягивается на десятки минут. Что помогает:
Excel.ScreenUpdating = Ложьи ручной пересчётExcel.Calculation = -4135на время заполнения; перед сохранением верните-4105(автоматический).- Запись блоком: создайте двумерный
COMSafeArrayс типомVT_VARIANT, заполните его методомSetValueи присвойте одним вызовомЛист.Range("A2:J50001").Value = Массив. Время падает в десятки раз. Порядок измерений сначала проверьте на таблице 2×3, чтобы строки и колонки не поменялись местами. - Комбинированный приём: сформировать XLSX табличным документом, а COM использовать только для «доводки» — открыть файл и добавить формулы или автофильтр.
Табличный документ
Он держит весь файл в памяти процесса. На сотнях тысяч строк растёт потребление памяти рабочего процесса сервера. Разбейте выгрузку на файлы по периодам или по 100–200 тысяч строк.
Жёсткий предел самого Excel — 1 048 576 строк и 16 384 колонки на лист. Больше в один лист не поместится ни одним способом.
CSV для очень больших массивов
Запись = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8);
Запись.ЗаписатьСтроку("Код;Наименование;Остаток");
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Запись.ЗаписатьСтроку(Выборка.Код + ";" + СтрЗаменить(Выборка.Наименование, ";", ",")
+ ";" + Формат(Выборка.Остаток, "ЧГ=0; ЧРД=,"));
КонецЦикла;
Запись.Закрыть();
Разделитель ; и запятая в дробях — под русские региональные настройки Excel. Выборка читается построчно, память не растёт.
Ошибки COM-соединения и корректное закрытие Excel
Главная беда COM-выгрузки — «зомби» EXCEL.EXE. Excel остаётся висеть, если код упал между созданием объекта и Quit(). Через неделю у пользователя в диспетчере задач 30 процессов и тормозит весь компьютер.
Правила, которые закрывают проблему:
- ✅ Создание объекта и всю работу оборачивайте в
Попытка … Исключение, аQuit()вызывайте после блока, как в примере выше, — он выполнится и при ошибке. - ✅ После
Quit()присвойте переменнойНеопределено, чтобы 1С отпустила ссылку на COM-объект. - ✅ Не храните COM-объект в реквизите формы или глобальной переменной между вызовами.
- ✅
Книга.Close(Ложь)закрывает книгу без вопроса о сохранении.
Если процессы уже накопились, их снимают в диспетчере задач. Предупредите пользователя: открытые у него вручную книги Excel закроются без сохранения.
Веб-клиент, тонкий клиент и сервер на Linux
В тонком клиенте под Windows работают оба способа. COM — только в процедурах с директивой &НаКлиенте и только при установленном Excel.
В веб-клиенте COM-объекты недоступны, а записать файл прямо на диск пользователя код не может. Схема одна:
- На сервере сформировать табличный документ и записать во временный файл.
- Поместить двоичные данные во временное хранилище — функция
ВыгрузитьНаСервере()выше делает именно это. - На клиенте отдать файл браузеру.
&НаКлиенте
Процедура Выгрузить(Команда)
Адрес = ВыгрузитьНаСервере();
ФайловаяСистемаКлиент.СохранитьФайл(Неопределено, Адрес, "Выгрузка.xlsx");
КонецПроцедуры
ФайловаяСистемаКлиент — модуль Библиотеки стандартных подсистем, он есть во всех типовых конфигурациях на БСП. В самописной базе без БСП используйте асинхронный метод платформы НачатьПолучениеФайлаССервера. Синхронный ПолучитьФайл в веб-клиенте со запрещёнными модальными и синхронными вызовами выдаст ошибку.
Если сервер 1С стоит на Linux, COM там нет вовсе. Зато ТабличныйДокумент.Записать в XLSX работает одинаково на Windows и Linux. Регламентные выгрузки в сетевую папку делайте этим способом. Права на запись в папку нужны учётной записи, под которой запущена служба сервера 1С, а не пользователю, который настроил задание.
Частые вопросы
Можно ли выгрузить в Excel формулы без COM?
Почему выгрузка работает у программиста, а у бухгалтера падает?
C:\Выгрузка\, которого нет на его компьютере. Выгрузка через табличный документ от этого не зависит.Как выгружать в Excel по расписанию?
Как выгрузить в Excel без программирования?
Ещё → Вывести список, а затем сохраните полученную таблицу.В каком виде через COM попадают даты?
Лист.Columns("C").NumberFormat = "dd.mm.yyyy".