В процессе разработки в среде 1С часто возникает задача выгрузки отчетности или печатных форм в формат Excel. Ситуация усложняется, когда пользователю необходимо получить не ворох отдельных файлов, а одну структурированную книгу Excel, где каждый табличный документ (ТабличныйДокумент) расположен на отдельном листе.
Традиционный путь решения этой задачи через COM-соединение с приложением Excel часто оказывается крайне медленным и нестабильным, особенно при работе на сервере или при обработке десятков тяжелых документов. В этой статье мы подробно разберем, как решить эту задачу быстро, современно и без использования стороннего программного обеспечения, а также как оптимизировать работу на старых версиях платформ 1С.
Начиная с версии платформы 1С:Предприятие 8.3.12, разработчикам стал доступен великолепный встроенный инструмент — ПакетОтображаемыхДокументов. Он позволяет объединить несколько табличных документов в один контейнер и сохранить его напрямую в многостраничный файл xlsx или xls в один вызов метода, не прибегая к COM-объектам и не требуя установленного Microsoft Excel на сервере или компьютере пользователя.
Давайте разберем по шагам, как реализовать этот алгоритм:
ПакетОтображаемыхДокументов.Записать для сохранения готовой книги.Посмотрим на практический пример кода, реализующий эту схему:
// Предположим, у нас есть массив табличных документов МасТабДоков
// и массив имен для будущих листов МасИменЛистов
Книга = Новый ПакетОтображаемыхДокументов;
Для Индекс = 0 По МасТабДоков.ВГраница() Цикл
ТекущийТабДок = МасТабДоков[Индекс];
ИмяЛиста = МасИменЛистов[Индекс];
// Помещаем табличный документ во временное хранилище
АдресХранилища = ПоместитьВоВременноеХранилище(ТекущийТабДок);
// Добавляем элемент в состав пакета
ЭлементПакета = Книга.Состав.Добавить();
ЭлементПакета.Данные = АдресХранилища;
// Задаем имя листа, которое будет отображаться в Excel
ЭлементПакета.Имя = ИмяЛиста;
КонецЦикла;
// Записываем итоговый файл в формате XLSX
ПутьКФайлу = "C:\Temp\ИтоговыйОтчет.xlsx";
Книга.Записать(ПутьКФайлу, ТипФайлаПакетаОтображаемыхДокументов.XLSX);
Важное примечание: Этот метод выполняется практически мгновенно, так как преобразование данных происходит на уровне платформы без запуска тяжелых внешних процессов. Однако помните о важном нюансе. Даже если вы обновили платформу до версии 8.3.12+, этот метод может выдавать ошибку компиляции или выполнения, если у вашей информационной базы в конфигураторе установлен Режим совместимости со старыми версиями (например, «8.3.10» или ниже). Для корректной работы метода необходимо отключить или повысить режим совместимости конфигурации.
Если специфика вашего проекта или ограничения инфраструктуры не позволяют обновить платформу 1С либо отключить режим совместимости, вам придется использовать COM-объект Excel.Application. Однако стандартный код, открывающий каждый временный лист по отдельности, работает очень медленно. Основная причина медлительности — постоянная перерисовка интерфейса Excel, обработка внутренних событий и пересчет формул при каждом открытии книги.
Выясним причину медленной работы и устраним ее с помощью оптимизации свойств COM-соединения. Мы отключим обновление экрана (ScreenUpdating), предупреждения (DisplayAlerts), интерактивность приложения и переведем расчет формул в ручной режим.
Рассмотрим подробнее оптимизированный код работы с COM-объектом:
// Инициализируем COM-объект Excel
Попытка
ОбъектЭкспорт = Новый COMОбъект("Excel.Application");
Исключение
Предупреждение("Не удалось запустить Excel. Возможно, программа не установлена на компьютере.");
Возврат;
КонецПопытки;
// Отключаем ресурсоемкие функции Excel для ускорения работы
ОбъектЭкспорт.ScreenUpdating = Ложь;
ОбъектЭкспорт.DisplayAlerts = Ложь;
ОбъектЭкспорт.Interactive = Ложь;
// Отключаем автоматический пересчет формул (переводим в ручной режим xlCalculationManual)
ОбъектЭкспорт.Calculation = -4135;
// Создаем итоговую книгу
КнигаОбщая = ОбъектЭкспорт.Workbooks.Add;
КоличествоПервыхСтраниц = КнигаОбщая.WorkSheets.Count;
Папка_TEMP = КаталогВременныхФайлов();
ВременныйФайл = Папка_TEMP + "temp_export_sheet.xls";
p = 0;
Для Каждого ТабДок из МасТабДоков Цикл
// Записываем ТабДок во временный XLS файл
ТабДок.Записать(ВременныйФайл, ТипФайлаТабличногоДокумента.XLS97);
// Открываем временный файл (теперь это происходит намного быстрее)
КнигаВременная = ОбъектЭкспорт.Workbooks.Open(ВременныйФайл);
Лист = КнигаВременная.WorkSheets(1);
// Назначаем имя листу
Лист.Name = ТабДок.ИспользуемоеИмяФайла;
// Копируем лист в общую книгу
Лист.Copy(, КнигаОбщая.WorkSheets(КоличествоПервыхСтраниц + p));
// Закрываем временную книгу без сохранения изменений
КнигаВременная.Close(Ложь);
p = p + 1;
УдалитьФайлы(ВременныйФайл);
КонецЦикла;
// Удаляем пустые листы, созданные Excel по умолчанию в новой книге
Для i = 1 по КоличествоПервыхСтраниц Цикл
КнигаОбщая.WorkSheets(1).Delete;
КонецЦикла;
// Сохраняем итоговую книгу (формат xls97/2003 - 56, формат xlsx - 51)
ПутьКФайлу = Папка_TEMP + "ИтоговыйФайл.xls";
КнигаОбщая.SaveAs(ПутьКФайлу, 56);
// Обязательно возвращаем настройки Excel в исходное состояние
ОбъектЭкспорт.Calculation = -4105; // xlCalculationAutomatic
ОбъектЭкспорт.ScreenUpdating = Истина;
ОбъектЭкспорт.DisplayAlerts = Истина;
ОбъектЭкспорт.Interactive = Истина;
// Закрываем приложение Excel
ОбъектЭкспорт.Quit();
ОбъектЭкспорт = Неопределено;
Этот простой шаг по отключению графической оболочки и автовычислений позволяет ускорить работу кода в 3–5 раз, делая процесс экспорта вполне комфортным для конечного пользователя.
Для продвинутых разработчиков, желающих получить максимальное быстродействие на серверах под управлением Linux (где COM-объекты Windows недоступны в принципе), существует альтернативный способ. Файлы формата xlsx — это обычные ZIP-архивы, содержащие разметку XML.
Проанализируем этот подход по шагам:
ТабличныйДокумент в отдельный файл xlsx штатными средствами 1С с помощью метода ТабДок.Записать(Путь, ТипФайлаТабличногоДокумента.XLSX).ЧтениеZipФайла и ЗаписьZipФайла, мы распаковываем эти файлы во временные папки.sheet1.xml, sheet2.xml и т.д.) из папок других документов в папку базового документа.[Content_Types].xml регистрируем пути ко всем новым добавленным листам.xl/_rels/workbook.xml.rels прописываем связи (Relationships) с уникальными идентификаторами для каждого нового листа.xl/workbook.xml регистрируем отображаемые имена вкладок и связываем их с соответствующими идентификаторами связей.xlsx.Этот способ требует детального понимания структуры XML-схем документов OpenXML, однако он обеспечивает непревзойденную скорость обработки и абсолютную независимость от операционной системы и сторонних программных пакетов.
Если вам приходится работать на платформах семейства 1С v7.7 или ранних версиях 1С v8 со старым форматом xls, идеальным выбором станет использование свободно распространяемой библиотеки Йоксель (Yoksel). Она подключается в качестве внешней компоненты и способна мгновенно собирать файлы табличных документов 1С (формат MXL) в единый многостраничный файл Excel, идеально сохраняя шрифты, цвета, объединения ячеек и ширину колонок.
Какое бы решение вы ни выбрали — современный встроенный ПакетОтображаемыхДокументов, оптимизированный COM-скрипт или низкоуровневую работу с XML — всегда ориентируйтесь на текущую версию платформы вашей информационной базы и требования к производительности системы.