Выгрузка таблицы значений в файл XLSX: код, COM и CSV

· 9 мин

Содержание

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

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

Что решить до выгрузки

Три вопроса определяют, какой код писать. Ответьте на них заранее, иначе файл окажется не там или не в том виде.

  • 🖥️ Где выполняется код. Таблица значений живёт на сервере. Метод Записать(), вызванный на сервере, создаёт файл на диске сервера, а не на компьютере пользователя.
  • 📦 Есть ли Excel у пользователя. Табличному документу Excel не нужен. COM-объекту нужен установленный Microsoft Excel и Windows.
  • 📏 Сколько строк. До десятков тысяч строк подходит любой способ. На сотнях тысяч табличный документ съедает память, а COM работает медленно, если писать по ячейке.

В управляемой форме таблица хранится в реквизите типа ДанныеФормыКоллекция. Чтобы получить настоящую таблицу значений, на сервере вызовите РеквизитФормыВЗначение("ИмяРеквизита").

Лимиты самого Excel тоже стоит держать в голове: в формате XLSX на листе помещается 1 048 576 строк, в старом XLS — только 65 536.

Стандартные средства платформы: вывод в табличный документ и запись XLSX

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

Подходит, когда таблица отображается в любой форме — списке, обработке, отчёте.

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

Команда доступна, только если у пользователя есть право «Вывод». Если пункта нет в меню «Ещё», проверьте это право в профиле групп доступа.

Быстрый вариант в коде: построитель отчёта

Классический приём в три строки. Построитель сам создаёт шапку с именами колонок.

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

Минус — оформление построителя: заголовки, отступы и группировки не всегда нужны в выгрузке для Excel. Объект работает на сервере, в тонком и веб-клиенте его нет.

Полный контроль: заполнение ячеек вручную

Когда нужна чистая таблица «шапка + строки» без лишнего, заполняйте ячейки сами. Главный приём — числа и даты записывать как значения, а не как текст. Тогда в Excel они сразу считаются в формулах.

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

Ширину колонки задают через область колонки: ТабДок.Область("C" + Формат(НомерКолонки, "ЧГ=0")).ШиринаКолонки = 20. Формат с ЧГ=0 нужен, чтобы номер склеился со строкой без пробела-разделителя.

Сама запись — одна строка:

ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX);

Для старого Excel вместо XLSX укажите XLS. Для LibreOffice подойдёт ODS.

Как передать файл Excel на компьютер пользователя

Самая частая ловушка: код на сервере пишет файл в C:\Выгрузка.xlsx, пользователь ищет его у себя и не находит. В клиент-серверной базе файл лёг на диск сервера 1С.

Правильная схема — временный файл на сервере, двоичные данные во временное хранилище, получение на клиенте.

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

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

ФайловаяСистемаКлиент — модуль Библиотеки стандартных подсистем. Он есть в типовых конфигурациях (БП 3.0, ЗУП 3.1, УТ 11) и сам показывает диалог сохранения. В самописной конфигурации без БСП используйте метод глобального контекста ПолучитьФайл(Адрес, "Выгрузка.xlsx", Истина). Он синхронный и работает, только если в свойствах конфигурации разрешены модальные вызовы.

Ещё проще для разовых задач: верните табличный документ на клиент и вызовите ТабДок.Показать(). Пользователь сам сохранит его в XLSX через Файл → Сохранить как….

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

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

Медленный, но понятный вариант — запись по ячейкам:

&НаКлиенте
Процедура ВыгрузитьЧерезCOM(Данные, ПутьКФайлу)
	// Данные — массив структур, полученный с сервера
	Excel = Новый COMОбъект("Excel.Application");
	Попытка
		Excel.Visible = Ложь;
		Excel.DisplayAlerts = Ложь;
		Книга = Excel.Workbooks.Add();
		Лист = Книга.Worksheets(1);
		
		Лист.Cells(1, 1).Value = "Номенклатура";
		Лист.Cells(1, 2).Value = "Количество";
		
		НомерСтроки = 1;
		Для Каждого Элемент Из Данные Цикл
			НомерСтроки = НомерСтроки + 1;
			Лист.Cells(НомерСтроки, 1).Value = Элемент.Номенклатура;
			Лист.Cells(НомерСтроки, 2).Value = Элемент.Количество;
		КонецЦикла;
		
		Книга.SaveAs(ПутьКФайлу, 51); // 51 — формат xlsx
		Книга.Close(Ложь);
	Исключение
		Excel.Quit();
		ВызватьИсключение;
	КонецПопытки;
	Excel.Quit();
КонецПроцедуры

На клиент таблицу значений не передать. Поэтому на сервере преобразуйте её в массив структур с примитивными значениями: строки, числа, даты. Ссылки на справочники заранее переводите в строку через Строка().

Блок Попытка…Исключение с Excel.Quit() обязателен. Без него при любой ошибке в памяти остаётся невидимый процесс EXCEL.EXE. Через десяток запусков таких процессов становится много, и Excel перестаёт открывать файлы.

Код формата в SaveAs: 51 — книга XLSX, 56 — книга XLS.

XLSX и CSV без Excel: программное формирование файла

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

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

Что здесь сделано под Excel:

  • 🔤 Кодировка UTF8 — 1С пишет файл с меткой BOM, и Excel правильно показывает кириллицу. Вариант UTF8N пишет без BOM, и русский текст превращается в «кракозябры».
  • ➗ Разделитель ; — русская версия Excel ждёт точку с запятой, а не запятую.
  • 🔢 ЧГ=0 — без этого 1С вставит в число неразрывный пробел между разрядами, и Excel прочитает «1 250» как текст.
  • 📝 Строки в кавычках с удвоением внутренних кавычек — иначе название «ООО «Ромашка»; филиал» разорвёт строку на две колонки.

Настоящий XLSX можно собрать и вручную: это ZIP-архив с XML-файлами внутри. В 1С для этого есть ЗаписьXML и ЗаписьZipФайла. Но схема Office Open XML объёмная, и на практике так делают редко — только когда нужен XLSX на сервере Linux с оформлением, которое табличный документ не передаёт.

Ошибки, кодировка и типы данных при экспорте

Большая часть проблем всплывает уже в Excel, когда файл открыли и что-то выглядит не так.

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

Отдельно о датах. Пустая дата в 1С — это 01.01.0001. В Excel она выглядит как мусор, поэтому перед выгрузкой проверяйте ЗначениеЗаполнено() и пишите пустую ячейку.

Большие объёмы: как ускорить выгрузку

На таблице в 200–300 тысяч строк разница между способами — минуты против секунд.

Табличный документ

  • Получайте Область ячейки один раз и заполняйте все её свойства через эту переменную, без повторных вызовов ТабДок.Область().
  • Не задавайте шрифт и рамки каждой ячейке строк. Оформите шапку, а данные оставьте без форматирования.
  • При нехватке памяти на сервере разбейте выгрузку на несколько файлов по 100–200 тысяч строк.

COM-объект: массив вместо ячеек

Каждое обращение Лист.Cells(i, j).Value — отдельный вызов между процессами 1С и Excel. 10 000 строк по 10 колонок — это 100 000 вызовов. Быстрее собрать данные в двумерный массив COMSafeArray и передать его в диапазон одной операцией:

КолвоСтрок = Данные.Количество();
КолвоКолонок = 2;
Массив = Новый COMSafeArray("VT_VARIANT", КолвоСтрок, КолвоКолонок);

Для Индекс = 0 По КолвоСтрок - 1 Цикл
	Массив.SetValue(Индекс, 0, Данные[Индекс].Номенклатура);
	Массив.SetValue(Индекс, 1, Данные[Индекс].Количество);
КонецЦикла;

Диапазон = Лист.Range(Лист.Cells(2, 1), Лист.Cells(КолвоСтрок + 1, КолвоКолонок));
Диапазон.Value = Массив;

Индексы COMSafeArray начинаются с нуля, а ячейки Excel — с единицы. Данные начинаются со второй строки, потому что первую занимает шапка. Отсюда КолвоСтрок + 1 в правой границе диапазона.

CSV для выгрузок «на миллион»

ЗаписьТекста не держит файл в памяти целиком, поэтому выгрузка таблицы в любой размер упирается только в саму таблицу значений. Если и она не помещается в память, выгружайте прямо из выборки запроса (Запрос.Выполнить().Выбрать()), без промежуточной таблицы значений.

Какой способ выгрузки таблицы значений в Excel выбрать

СпособНужен ExcelГде работаетСкорость на 100 000 строкОформлениеКогда выбирать
«Вывести список»НетЛюбой клиентЗависит от формыМинимальноеРазовая выгрузка пользователем
Построитель отчёта + ЗаписатьНетСерверХорошаяСвоё, построителяБыстрый код «лишь бы выгрузить»
Табличный документ вручную + XLSXНетСервер, клиент, LinuxХорошаяШрифты, ширина, типы ячеекОсновной вариант для обработок
COM по ячейкамДаТолько Windows-клиентНизкаяЛюбое: листы, формулы, фильтрыНебольшие таблицы по шаблону
COM + COMSafeArrayДаТолько Windows-клиентВысокаяЛюбоеБольшие таблицы со сложным оформлением
CSV через ЗаписьТекстаНетСервер, клиент, LinuxСамая высокаяНикакогоОгромные объёмы, загрузка в другие системы

Для обработки, которой будут пользоваться другие люди, выбирайте табличный документ и XLSX: он не зависит от установленного Office, работает в серверной базе на Linux и в веб-клиенте при передаче файла через временное хранилище.

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

Можно ли записать таблицу значений в Excel напрямую, без табличного документа?
Нет, у объекта ТаблицаЗначений нет метода записи в XLSX. Нужен посредник: табличный документ, COM-объект Excel или текстовый файл CSV.
Как выгрузить таблицу значений на несколько листов Excel?
Табличный документ записывает один лист. Для нескольких листов используйте COM-объект Excel: Книга.Worksheets.Add() добавляет лист, дальше заполнение как обычно.
Сохранятся ли при записи в XLSX объединения ячеек и цвета?
Да, основное оформление табличного документа переносится: шрифты, цвета, рамки, объединения, ширина колонок. Формулы Excel табличный документ не создаёт.
Работает ли выгрузка в веб-клиенте?
COM-объект в веб-клиенте недоступен. Табличный документ формируйте на сервере, а файл отдавайте через временное хранилище — браузер скачает его как обычный файл.
Как выгрузить таблицу значений во время отладки?
В режиме отладки вычислите выражение с вызовом своей функции выгрузки, например ТаблицаВТабДок(ТЗ).Записать(“C:\Temp\debug.xlsx”, ТипФайлаТабличногоДокумента.XLSX). Файл создастся там, где выполняется код.