Выгрузка в Excel из кода 1С: табличный документ, COM и CSV

· 9 мин

Содержание

Чтобы программно выгрузить данные из 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 = Неопределено;
    КонецЕсли;

КонецПроцедуры

Что здесь важно:

  1. DisplayAlerts = Ложь — Excel не покажет скрытый вопрос «Заменить файл?», из-за которого код повисает навсегда.
  2. Второй параметр SaveAs — формат файла: 51 это XLSX без макросов, 56 — старый XLS.
  3. В свойство Formula формулу пишут с английскими именами функций (SUM, IF). Для русских (СУММ) есть FormulaLocal, но он зависит от языка Office у пользователя.
  4. Формат(НомерСтроки, "ЧГ=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 колонок это полмиллиона вызовов, выгрузка растягивается на десятки минут. Что помогает:

  1. Excel.ScreenUpdating = Ложь и ручной пересчёт Excel.Calculation = -4135 на время заполнения; перед сохранением верните -4105 (автоматический).
  2. Запись блоком: создайте двумерный COMSafeArray с типом VT_VARIANT, заполните его методом SetValue и присвойте одним вызовом Лист.Range("A2:J50001").Value = Массив. Время падает в десятки раз. Порядок измерений сначала проверьте на таблице 2×3, чтобы строки и колонки не поменялись местами.
  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-объекты недоступны, а записать файл прямо на диск пользователя код не может. Схема одна:

  1. На сервере сформировать табличный документ и записать во временный файл.
  2. Поместить двоичные данные во временное хранилище — функция ВыгрузитьНаСервере() выше делает именно это.
  3. На клиенте отдать файл браузеру.
&НаКлиенте
Процедура Выгрузить(Команда)
    Адрес = ВыгрузитьНаСервере();
    ФайловаяСистемаКлиент.СохранитьФайл(Неопределено, Адрес, "Выгрузка.xlsx");
КонецПроцедуры

ФайловаяСистемаКлиент — модуль Библиотеки стандартных подсистем, он есть во всех типовых конфигурациях на БСП. В самописной базе без БСП используйте асинхронный метод платформы НачатьПолучениеФайлаССервера. Синхронный ПолучитьФайл в веб-клиенте со запрещёнными модальными и синхронными вызовами выдаст ошибку.

Если сервер 1С стоит на Linux, COM там нет вовсе. Зато ТабличныйДокумент.Записать в XLSX работает одинаково на Windows и Linux. Регламентные выгрузки в сетевую папку делайте этим способом. Права на запись в папку нужны учётной записи, под которой запущена служба сервера 1С, а не пользователю, который настроил задание.

Частые вопросы

Можно ли выгрузить в Excel формулы без COM?
Нет. Табличный документ сохраняет в XLSX только значения и оформление. Формулы, условное форматирование Excel и сводные таблицы добавляют через COM — например, открыв уже записанный файл.
Почему выгрузка работает у программиста, а у бухгалтера падает?
Чаще всего у бухгалтера нет Excel или стоит другой офисный пакет, и COM-объект не создаётся. Ещё одна причина — путь сохранения вроде C:\Выгрузка\, которого нет на его компьютере. Выгрузка через табличный документ от этого не зависит.
Как выгружать в Excel по расписанию?
Регламентным заданием на сервере: формируете табличный документ, записываете в XLSX в сетевую папку или отправляете вложением письма. COM в регламентных заданиях не используйте.
Как выгрузить в Excel без программирования?
Любой отчёт открывается как табличный документ: сохраните его через главное меню командой «Сохранить как» и выберите тип файла XLSX. Для списка документов или справочника сначала выполните Ещё → Вывести список, а затем сохраните полученную таблицу.
В каком виде через COM попадают даты?
Значение типа «Дата» 1С передаёт в Excel датой, а не строкой. Чтобы не показывалось время 00:00:00, задайте колонке формат: Лист.Columns("C").NumberFormat = "dd.mm.yyyy".