Таблица значений → файл xlsx: код для разработчика и путь для пользователя
Содержание
Быстрее всего выгрузить таблицу значений в 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 | .xlsx | 1 048 576 |
XLS | .xls | 65 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 к этому моменту может уже не отвечать.
Что ещё обрабатывать:
- Создание объекта. Если Excel не установлен или не зарегистрирован, конструктор падает с сообщением
Ошибка при вызове конструктора (COMОбъект). Покажите пользователю понятный текст и предложите выгрузку через табличный документ. - Занятый файл. Если пользователь держит прошлую выгрузку открытой, перезапись файла с тем же именем не пройдёт. Добавляйте к имени дату и время:
"Выгрузка_" + Формат(ТекущаяДатаСеанса(), "ДФ=yyyyMMdd_HHmmss") + ".xlsx". - Пустая таблица. Проверьте
ТЗ.Количество() = 0до создания файла и сообщите, что выгружать нечего. Пустая книга с одной шапкой только запутает. - Права на каталог. Служба сервера 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. Если данных больше, разбивайте выгрузку на несколько файлов.
Выгрузка без программирования: команда «Вывести список»
Если таблица значений показана на форме (табличная часть, результат обработки, список), разработчик пользователю не нужен.
- Щёлкните по таблице на форме, чтобы она стала активной.
- Откройте меню
Ещёнад таблицей и выберитеВывести список…. - Отметьте колонки, которые нужны в файле, и нажмите
ОК. Откроется табличный документ. - Нажмите
Ctrl+Sили выберите в главном менюФайл → Сохранить как. - В поле типа файла выберите формат xlsx и сохраните.
Команда доступна, если у пользователя есть право «Вывод» в его ролях. Нет пункта в меню — проверяйте права у администратора базы.
Разработчику, который смотрит таблицу значений в отладчике, проще всего вывести её на временную форму обработки и выгрузить тем же Вывести список, чем писать отдельный код.
Частые проблемы с выгрузкой и их решение
ЗаписьТекста с КодировкаТекста.UTF8 либо открывайте файл в Excel через импорт данных с явным выбором кодировки.СодержитЗначение и Значение, в CSV — через Формат(Число, "ЧРД=,; ЧГ=0").Записать() выполнился на сервере 1С, и файл лежит на его диске. Передайте двоичные данные через временное хранилище и сохраните на клиенте.NumberFormat = "@") до записи значений.Excel.Quit(). Добавьте его в ветку Исключение, а накопившиеся процессы завершите вне рабочего времени.Частые вопросы
Нужен ли установленный Excel, чтобы сохранить xlsx из 1С?
Записать() табличного документа формирует xlsx сам. Excel нужен только для выгрузки через COM-объект.