При разработке сложных отчетов или систем выгрузки данных часто возникает задача: сохранить несколько независимых табличных документов (например, разные разделы отчета) в одну книгу Excel, где каждый документ будет располагаться на отдельном листе. Стандартный метод Записать() объекта ТабличныйДокумент позволяет сохранить только одну таблицу в один файл. Если вызвать его несколько раз для одного и того же пути, файл будет просто перезаписываться.
В данной статье мы разберем несколько подходов к решению этой задачи: от классического использования COM-объектов (подходит для старых конфигураций и обычных форм) до современных штатных механизмов платформы 1С:Предприятие 8.3 и БСП.
Этот метод является универсальным для систем, где установлен пакет Microsoft Office. Основная идея заключается в том, чтобы сохранить каждый табличный документ во временный файл, а затем программно перенести листы из этих файлов в одну общую книгу. Рассмотрим алгоритм реализации подробнее.
Для начала проанализируем программный код, который позволяет автоматизировать этот процесс. Мы будем использовать объект Excel.Application для управления внешним приложением.
// Создаем подключение к Excel
Попытка
ExcelПриложение = Новый COMОбъект("Excel.Application");
Исключение
Сообщить("Microsoft Excel не установлен на данном компьютере!");
Возврат;
КонецПопытки;
// Создаем новую рабочую книгу, которая станет итоговым файлом
ИтоговаяКнига = ExcelПриложение.Workbooks.Add();
// Отключаем визуальное обновление и запросы системы для ускорения работы
ExcelПриложение.ScreenUpdating = Ложь;
ExcelПриложение.DisplayAlerts = Ложь;
// Массив наших табличных документов (предположим, они уже сформированы)
МассивТабДоков = Новый Массив;
МассивТабДоков.Добавить(ЭлементыФормы.ТабДок1);
МассивТабДоков.Добавить(ЭлементыФормы.ТабДок2);
Для Каждого ТекущийТабДок Из МассивТабДоков Цикл
// Формируем временное имя файла для промежуточного сохранения
ВременныйФайл = ПолучитьИмяВременногоФайла("xls");
ТекущийТабДок.Записать(ВременныйФайл, ТипФайлаТабличногоДокумента.XLS);
// Открываем временный файл во втором экземпляре (книге)
ВременнаяКнига = ExcelПриложение.Workbooks.Open(ВременныйФайл);
// Копируем первый лист из временной книги в конец итоговой книги
ВременнаяКнига.Sheets(1).Copy(ИтоговаяКнига.Sheets(ИтоговаяКнига.Sheets.Count));
// Закрываем временную книгу без сохранения
ВременнаяКнига.Close(Ложь);
// Удаляем временный файл с диска
УдалитьФайлы(ВременныйФайл);
КонецЦикла;
// Удаляем пустые листы, созданные Excel по умолчанию при создании книги
Пока ИтоговаяКнига.Sheets.Count > МассивТабДоков.Количество() Цикл
ИтоговаяКнига.Sheets(1).Delete();
КонецЦикла;
// Включаем настройки обратно и показываем результат
ExcelПриложение.ScreenUpdating = Истина;
ExcelПриложение.DisplayAlerts = Истина;
ExcelПриложение.Visible = Истина;
Разберем важные моменты в этом коде. Мы используем метод Copy() объекта Sheet. Это гораздо эффективнее, чем выделять все ячейки через Cells.Select и использовать буфер обмена через Paste, как предлагалось в некоторых сообщениях на форуме. Метод Copy() сохраняет форматирование, ширину колонок и параметры печати гораздо точнее. Кроме того, использование буфера обмена может мешать пользователю, если он параллельно работает в других приложениях.
Если ваши таблицы содержат тысячи строк, выгрузка может затянуться. Чтобы минимизировать время ожидания, обязательно установите следующие свойства объекта ExcelПриложение:
xlCalculationManual). Это критично, если в таблицах есть формулы.Не забудьте в блоке Попытка...Исключение или в конце процедуры вернуть эти параметры в исходное состояние, иначе Excel у пользователя может начать вести себя некорректно.
Современные версии платформы 1С позволяют избежать использования медленного и нестабильного COM-соединения. Начиная с версии 8.3.10, в системе появились механизмы, позволяющие объединять табличные документы программно. Рассмотрим ситуацию, когда мы можем использовать встроенный метод Записать() для коллекции.
Выясним, как это работает. Если мы используем механизм печати БСП или формируем пакет документов, мы можем поместить их в массив и воспользоваться методом ТабличныйДокумент.Записать(), но есть нюанс: стандартный метод объекта ТабличныйДокумент все равно пишет только себя. Однако в Библиотеке стандартных подсистем (БСП) реализован специальный метод для решения нашей задачи.
Если ваша конфигурация построена на базе БСП (УТ 11, ERP 2, Бухгалтерия 3.0), используйте метод УправлениеПечатью.ЗаписатьТабличныеДокументыВФайл. Это самый "чистый" и быстрый способ. Он работает на стороне сервера и не требует установленного Excel.
// Подготовим коллекцию документов
ОбластьПечати = Новый Массив;
// Первый лист
СтрЛист1 = Новый Структура;
СтрЛист1.Вставить("ТабличныйДокумент", ТабДок1);
СтрЛист1.Вставить("ИмяЛиста", "Продажи");
ОбластьПечати.Добавить(СтрЛист1);
// Второй лист
СтрЛист2 = Новый Структура;
СтрЛист2.Вставить("ТабличныйДокумент", ТабДок2);
СтрЛист2.Вставить("ИмяЛиста", "Остатки");
ОбластьПечати.Добавить(СтрЛист2);
// Путь к файлу
ПутьКФайлу = "C:\Reports\ОбщийОтчет.xlsx";
// Вызываем метод БСП
УправлениеПечатью.ЗаписатьТабличныеДокументыВФайл(ПутьКФайлу, ОбластьПечати);
Проанализируем преимущества этого метода:
.xlsx напрямую, что в десятки раз быстрее, чем управление приложением Excel через команды Windows.Если вам требуется еще более тонкая настройка или вы работаете на очень старой платформе, но без Excel на сервере, можно вспомнить, что формат .xlsx — это обычный ZIP-архив, внутри которого находятся XML-файлы. Программисты 1С могут использовать объект ЧтениеZipФайла и ЗаписьZipФайла вместе с ЧтениеXML, чтобы "склеить" несколько файлов в один.
Алгоритм действий в этом случае следующий:
ТабличныйДокумент в отдельный .xlsx файл.workbook.xml, добавляя ссылки на все листы (worksheets)..xlsx.Этот способ крайне трудоемок и рекомендуется только в исключительных случаях, когда штатные методы платформы недоступны, а COM использовать нельзя.
Проанализируем типичные ошибки, с которыми сталкиваются разработчики при выгрузке больших объемов данных:
1. Ограничение количества строк. При использовании старого формата XLS (Excel 97-2003) вы ограничены 65 536 строками на одном листе. Если данных больше, 1С выдаст ошибку или обрежет таблицу. Всегда используйте ТипФайлаТабличногоДокумента.XLSX для современных задач.
2. Разрядность систем. Если ваш сервер 1С 64-битный, а Microsoft Excel установлен 32-битный, прямое создание Новый COMОбъект("Excel.Application") на сервере может завершиться ошибкой доступа. В этом случае код необходимо выполнять на стороне клиента (в контексте &НаКлиенте).
3. Имена листов. Excel накладывает строгие ограничения на имена листов: не более 31 символа, отсутствие спецсимволов вроде / \ ? * [ ]. Перед назначением имени листа обязательно очищайте строку от запрещенных знаков, иначе метод сохранения вызовет исключение.
Выясним, какой метод выбрать. Если вы работаете на управляемых формах и версии платформы выше 8.3.10 — однозначно выбирайте штатные средства или функции БСП. Если же вы поддерживаете старую конфигурацию на обычных формах (например, УПП 1.3), метод с временными файлами и COM-объектом, описанный в Способе 1, остается самым надежным и проверенным решением.