Таблица значений → файл xlsx: код для разработчика и путь для пользователя

· 10 мин

Содержание

Быстрее всего выгрузить таблицу значений в Excel из 1С так: вывести её в ТабличныйДокумент и вызвать ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX). Excel на компьютере для этого не нужен, код работает на сервере под Windows и Linux.

COM-объект Excel.Application нужен, только когда требуется настоящая книга с формулами, несколькими листами или готовым шаблоном. Если же таблица уже показана на форме, пользователь выгрузит её сам, без строчки кода, через команду Ещё → Вывести список.

Какой способ выгрузки в Excel выбрать

Таблица значений существует только на сервере: в тонком и веб-клиенте этого типа нет. Отсюда главное правило: файл формируется на сервере, а клиенту передаются двоичные данные через временное хранилище.

СпособКогда подходитНужен ExcelОграничения
📄 Табличный документ + Записать()Почти всегда, это вариант по умолчаниюНетОдин лист в файле
🧩 COM Excel.ApplicationФормулы, шаблон, несколько листовДа, на той машине, где выполняется кодТолько Windows, медленно на больших объёмах
📝 CSV через ЗаписьТекста200 тысяч строк и больше, обмен с другими системамиНетБез оформления, разделитель и кодировка — на вашей стороне
🖱 Ещё → Вывести списокРазовая выгрузка пользователемНетТолько то, что видно в таблице формы

Если сомневаетесь, берите табличный документ. Он переживёт переезд базы на Linux-сервер, а COM-выгрузка в этот момент перестанет работать.

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

Вариант 1. Построитель отчёта: три строки кода

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

&НаСервере
Функция ТаблицаВТабличныйДокумент(ТЗ)
    ТабДок = Новый ТабличныйДокумент;
    Построитель = Новый ПостроительОтчета;
    Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТЗ);
    Построитель.Вывести(ТабДок);
    Возврат ТабДок;
КонецФункции

Плюс подхода в скорости написания. Минус в том, что оформлением управлять почти нельзя: шапка и ширина колонок будут такими, какими их выведет построитель.

Вариант 2. Ручной вывод по ячейкам

Ручной цикл даёт полный контроль: свои заголовки, жирная шапка, числа именно числами. Код ниже готов к вставке в модуль формы или общий модуль.

&НаСервере
Функция ВывестиТаблицуВручную(ТЗ)
    ТабДок = Новый ТабличныйДокумент;
    ЖирныйШрифт = Новый Шрифт(, , Истина);

    // Шапка
    НомКол = 0;
    Для Каждого Колонка Из ТЗ.Колонки Цикл
        НомКол = НомКол + 1;
        Область = ТабДок.Область(1, НомКол, 1, НомКол);
        Область.Текст = ?(ПустаяСтрока(Колонка.Заголовок), Колонка.Имя, Колонка.Заголовок);
        Область.Шрифт = ЖирныйШрифт;
    КонецЦикла;

    // Строки
    НомСтр = 1;
    Для Каждого СтрокаТЗ Из ТЗ Цикл
        НомСтр = НомСтр + 1;
        НомКол = 0;
        Для Каждого Колонка Из ТЗ.Колонки Цикл
            НомКол = НомКол + 1;
            Значение = СтрокаТЗ[Колонка.Имя];
            Область = ТабДок.Область(НомСтр, НомКол, НомСтр, НомКол);
            Если ТипЗнч(Значение) = Тип("Число") Тогда
                Область.СодержитЗначение = Истина;
                Область.Значение = Значение;
            ИначеЕсли ТипЗнч(Значение) = Тип("Дата") Тогда
                Область.Текст = ?(ЗначениеЗаполнено(Значение), Формат(Значение, "ДФ=dd.MM.yyyy"), "");
            Иначе
                Область.Текст = Строка(Значение);
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;

    ТабДок.ФиксацияСверху = 1;
    Возврат ТабДок;
КонецФункции

Почему числа выводятся через Значение, а не через Текст: строка вида 1 234,56 содержит неразрывный пробел-разделитель групп. Excel видит в ней текст, ставит зелёный треугольник, и формула СУММ по колонке даёт ноль.

Если всё же нужно число в виде строки, форматируйте его без разделителя групп: Формат(Сумма, "ЧГ=0"). Иначе Excel не распознает его как число.

Что делать со ссылками и пустыми значениями

  • 🔗 Ссылка на справочник или документ при выводе через Строка() превращается в представление: наименование или «Реализация товаров … от …». Код или ИНН придётся положить в отдельную колонку ещё на этапе запроса.
  • 📅 Пустая дата 01.01.0001 в Excel выглядит странно. В коде выше она заменяется пустой строкой.
  • ✅ Булево Строка() превращает в «Да» / «Нет». Если файл читает другая программа, явно выводите 1 и 0.

Как записать файл xlsx и отдать его пользователю

Метод Записать() сохраняет файл в файловой системе той машины, где выполняется код. В клиент-серверной базе это сервер 1С, а не компьютер бухгалтера. Поэтому схема такая: временный файл на сервере → двоичные данные → временное хранилище → сохранение на клиенте.

&НаСервере
Функция ПодготовитьФайлExcel()
    ТЗ = ПолучитьДанныеДляВыгрузки(); // ваш запрос или расчёт
    ТабДок = ВывестиТаблицуВручную(ТЗ);

    ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
    ТабДок.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.XLSX);
    Адрес = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ИмяВременногоФайла), УникальныйИдентификатор);
    УдалитьФайлы(ИмяВременногоФайла);

    Возврат Адрес;
КонецФункции

&НаКлиенте
Процедура ВыгрузитьВExcel(Команда)
    Адрес = ПодготовитьФайлExcel();
    ПолучитьФайл(Адрес, "Выгрузка.xlsx", Истина);
КонецПроцедуры

ПолучитьФайл открывает модальный диалог. Если в свойствах конфигурации модальность запрещена (так в типовых конфигурациях на БСП), используйте вместо него ФайловаяСистемаКлиент.СохранитьФайл(Неопределено, Адрес, "Выгрузка.xlsx").

Какой тип файла указать

Значение ТипФайлаТабличногоДокументаРасширениеПредел строк на листе
XLSX.xlsx1 048 576
XLS.xls65 536
ODS.ods— для LibreOffice
MXL.mxlвнутренний формат 1С

Расширение в имени файла должно совпадать с выбранным типом. Если записать XLS в файл .xlsx, Excel при открытии предупредит, что формат не соответствует расширению.

Выгрузка в CSV для больших и «машинных» файлов

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

&НаСервере
Процедура ЗаписатьCSV(ТЗ, ИмяФайла)
    Запись = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8);
    Части = Новый Массив;

    Для Каждого Колонка Из ТЗ.Колонки Цикл
        Части.Добавить(Колонка.Имя);
    КонецЦикла;
    Запись.ЗаписатьСтроку(СтрСоединить(Части, ";"));

    Для Каждого СтрокаТЗ Из ТЗ Цикл
        Части.Очистить();
        Для Каждого Колонка Из ТЗ.Колонки Цикл
            Значение = СтрокаТЗ[Колонка.Имя];
            Если ТипЗнч(Значение) = Тип("Число") Тогда
                Текст = Формат(Значение, "ЧРД=,; ЧГ=0; ЧН=0");
            ИначеЕсли ТипЗнч(Значение) = Тип("Дата") Тогда
                Текст = Формат(Значение, "ДФ=dd.MM.yyyy");
            Иначе
                Текст = Строка(Значение);
            КонецЕсли;
            Части.Добавить("""" + СтрЗаменить(Текст, """", """""") + """");
        КонецЦикла;
        Запись.ЗаписатьСтроку(СтрСоединить(Части, ";"));
    КонецЦикла;

    Запись.Закрыть();
КонецПроцедуры

Каждое значение берётся в кавычки, а кавычки внутри удваиваются. Так точка с запятой в наименовании «ООО Ромашка; филиал» не разорвёт строку на две колонки. Кодировка UTF-8 в 1С пишется с меткой BOM, и Excel по ней правильно показывает кириллицу.

Выгрузка через COM-объект Excel.Application

COM-соединение управляет запущенным Excel так же, как макрос VBA. Это единственный способ из 1С вписать данные в готовый шаблон с формулами, сводными таблицами или несколькими листами.

Условия: Windows и установленный Microsoft Excel там, где выполняется код. Для &НаСервере это сервер 1С, для &НаКлиенте в тонком клиенте — компьютер пользователя.

&НаСервере
Процедура ВыгрузитьЧерезCOM(ТЗ, ИмяФайла)
    Excel = Неопределено;
    Попытка
        Excel = Новый COMОбъект("Excel.Application");
        Excel.Visible = Ложь;
        Excel.DisplayAlerts = Ложь;
        Excel.ScreenUpdating = Ложь;

        Книга = Excel.Workbooks.Add();
        Лист = Книга.Worksheets(1);
        КолвоКолонок = ТЗ.Колонки.Количество();

        Для НомКол = 1 По КолвоКолонок Цикл
            Лист.Cells(1, НомКол).Value = ТЗ.Колонки[НомКол - 1].Имя;
        КонецЦикла;

        НомСтр = 1;
        Для Каждого СтрокаТЗ Из ТЗ Цикл
            НомСтр = НомСтр + 1;
            Для НомКол = 1 По КолвоКолонок Цикл
                Лист.Cells(НомСтр, НомКол).Value = ЗначениеДляCOM(СтрокаТЗ[НомКол - 1]);
            КонецЦикла;
        КонецЦикла;

        Лист.Columns.AutoFit();
        Книга.SaveAs(ИмяФайла, 51); // 51 — xlsx, 56 — xls
        Книга.Close(Ложь);
        Excel.Quit();
    Исключение
        ТекстОшибки = ОписаниеОшибки();
        Если Excel <> Неопределено Тогда
            Попытка
                Excel.Quit();
            Исключение
            КонецПопытки;
        КонецЕсли;
        ВызватьИсключение "Выгрузка в Excel не выполнена: " + ТекстОшибки;
    КонецПопытки;
КонецПроцедуры

&НаСервере
Функция ЗначениеДляCOM(Значение)
    Если ТипЗнч(Значение) = Тип("Число") Или ТипЗнч(Значение) = Тип("Строка") Тогда
        Возврат Значение;
    ИначеЕсли ТипЗнч(Значение) = Тип("Дата") Тогда
        Возврат ?(ЗначениеЗаполнено(Значение), Значение, "");
    Иначе
        Возврат Строка(Значение);
    КонецЕсли;
КонецФункции

Функция ЗначениеДляCOM нужна потому, что ссылку на объект 1С передать в Excel нельзя, а пустая дата для него вне допустимого диапазона.

Заполнение готового шаблона

Вместо Workbooks.Add() откройте файл-шаблон: Книга = Excel.Workbooks.Open(ИмяШаблона). Данные пишите в нужные ячейки, а сохраняйте под новым именем через SaveAs, чтобы не испортить исходник.

Колонки с ИНН, КПП, артикулами из цифр перед заполнением переведите в текстовый формат: Лист.Columns(3).NumberFormat = "@". Иначе Excel срежет ведущие нули и покажет длинные числа в экспоненциальной записи.

Ошибки при выгрузке: как их перехватить и не оставить «висящий» Excel

Главная беда COM-выгрузки в том, что после исключения процесс EXCEL.EXE продолжает жить. На сервере такие процессы копятся десятками и съедают память. Поэтому Excel.Quit() стоит и в ветке Исключение, причём внутри своей Попытки: сам Excel к этому моменту может уже не отвечать.

Что ещё обрабатывать:

  1. Создание объекта. Если Excel не установлен или не зарегистрирован, конструктор падает с сообщением Ошибка при вызове конструктора (COMОбъект). Покажите пользователю понятный текст и предложите выгрузку через табличный документ.
  2. Занятый файл. Если пользователь держит прошлую выгрузку открытой, перезапись файла с тем же именем не пройдёт. Добавляйте к имени дату и время: "Выгрузка_" + Формат(ТекущаяДатаСеанса(), "ДФ=yyyyMMdd_HHmmss") + ".xlsx".
  3. Пустая таблица. Проверьте ТЗ.Количество() = 0 до создания файла и сообщите, что выгружать нечего. Пустая книга с одной шапкой только запутает.
  4. Права на каталог. Служба сервера 1С работает под своей учётной записью. Пишите во временный каталог через ПолучитьИмяВременногоФайла(), а не в произвольную папку на диске.

Если EXCEL.EXE уже накопились на сервере, их приходится завершать в диспетчере задач. Делайте это, когда выгрузки никто не запускает: у пользователя, который выгружает прямо сейчас, операция оборвётся с ошибкой.

Большие таблицы: как ускорить выгрузку в Excel

Скорость упирается в число обращений. Табличный документ работает внутри процесса 1С и справляется с десятками тысяч строк за секунды. COM делает отдельный межпроцессный вызов на каждую ячейку: 20 000 строк × 10 колонок — это 200 000 вызовов, и выгрузка растягивается на минуты.

Что помогает:

  • ⚡ В COM писать строку целиком. Один массив на строку вместо отдельных ячеек сокращает число вызовов в десять раз для 10 колонок:
Массив = Новый COMSafeArray("VT_VARIANT", КолвоКолонок);
Для НомКол = 0 По КолвоКолонок - 1 Цикл
    Массив.SetValue(НомКол, ЗначениеДляCOM(СтрокаТЗ[НомКол]));
КонецЦикла;
Лист.Range(Лист.Cells(НомСтр, 1), Лист.Cells(НомСтр, КолвоКолонок)).Value = Массив;
  • 🧮 Отключить пересчёт и перерисовку. Excel.ScreenUpdating = Ложь уже есть в примере. Для книги с формулами добавьте Excel.Calculation = -4135 (ручной пересчёт) и верните -4105 (автоматический) перед сохранением.
  • 🔀 Комбинировать способы. Сохраните данные через табличный документ в xlsx, а потом откройте этот файл через COM только ради оформления: автоширины, фильтра, закрепления шапки.
  • 📦 Готовить данные запросом. Отбор, группировку и итоги делайте в запросе, а не циклом по таблице значений перед выгрузкой.
  • 📝 Переходить на CSV. От 200–300 тысяч строк табличный документ заметно расходует память сервера. CSV пишется потоком и памяти почти не требует.
  • 📑 Помнить о пределе листа. В xlsx помещается 1 048 576 строк, в xls — 65 536. Если данных больше, разбивайте выгрузку на несколько файлов.

Выгрузка без программирования: команда «Вывести список»

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

  1. Щёлкните по таблице на форме, чтобы она стала активной.
  2. Откройте меню Ещё над таблицей и выберите Вывести список….
  3. Отметьте колонки, которые нужны в файле, и нажмите ОК. Откроется табличный документ.
  4. Нажмите Ctrl+S или выберите в главном меню Файл → Сохранить как.
  5. В поле типа файла выберите формат xlsx и сохраните.

Команда доступна, если у пользователя есть право «Вывод» в его ролях. Нет пункта в меню — проверяйте права у администратора базы.

Разработчику, который смотрит таблицу значений в отладчике, проще всего вывести её на временную форму обработки и выгрузить тем же Вывести список, чем писать отдельный код.

Частые проблемы с выгрузкой и их решение

Диагностика: выберите симптом

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

Нужен ли установленный Excel, чтобы сохранить xlsx из 1С?
Нет. Метод Записать() табличного документа формирует xlsx сам. Excel нужен только для выгрузки через COM-объект.
Работает ли выгрузка в Excel в веб-клиенте?
Да, если файл формируется на сервере через табличный документ и передаётся через временное хранилище. COM-объект в веб-клиенте недоступен.
Можно ли выгрузить таблицу значений из фоновой процедуры?
Да. Сформируйте файл на сервере, положите двоичные данные во временное хранилище по адресу, который форма передала в фоновое задание, и заберите их на клиенте после завершения.
Чем XLSX лучше XLS при выгрузке?
Файл меньше по размеру, на листе помещается больше миллиона строк вместо 65 536, и его без проблем открывают современные версии Excel и LibreOffice.