При работе с табличными документами в платформе 1С:Предприятие разработчики часто сталкиваются с необходимостью выгрузки данных во внешние форматы, такие как Excel. Типичная задача — сформировать чистый список данных (например, для отправки в государственные информационные системы, такие как ЕГИССО) без лишних декоративных элементов, заголовков или пустых строк, которые присутствуют в исходном макете конфигурации.
В этой статье мы подробно разберем, почему возникает проблема дублирования или вывода лишних строк макета, почему популярные «обходные пути» (костыли) только вредят стабильности системы, и как реализовать выгрузку правильно и профессионально с точки зрения стандартов разработки 1С.
Рассмотрим классическую ошибку начинающего разработчика. Код инициализации и выгрузки в первом сообщении темы выглядел следующим образом:
&НаСервере
Процедура ВыгрузитьНаСервере()
Об = РеквизитФормыВЗначение("Объект");
ТабДок = Об.ПолучитьМакет("Макет");
ОбластьПараметров = ТабДок.ПолучитьОбласть("Строки");
Для Каждого Стр Из Объект.СписокЛюдей Цикл
ОбластьПараметров.Параметры.Контрагент = Стр.Контрагент;
ОбластьПараметров.Параметры.Сумма = Стр.Сумма;
ТабДок.Вывести(ОбластьПараметров);
КонецЦикла;
ТабДок.Записать("C:\Выгрузка.xls", ТипФайлаТабличногоДокумента.XLS);
КонецПроцедуры
Давайте проанализируем, что происходит в памяти сервера при выполнении этого кода. Метод ПолучитьМакет("Макет") возвращает не пустой лист, а полную копию оригинального макета со всеми его статическими текстами, оформлением, рамками и шапкой, которые были нарисованы в конфигураторе. Этот объект уже содержит заполненную визуальную часть.
Когда мы вызываем метод ТабДок.Вывести(ОбластьПараметров), платформа 1С не перезаписывает существующие строки, а последовательно добавляет (копирует) новые строки в самый конец уже существующего документа-шаблона. В результате итоговый файл Excel содержит сначала оригинальный шаблон макета (включая шапку и пустые строки параметров), а затем — заполненные строки из цикла. Это приводит к появлению «мусорных» данных в начале файла.
Иногда разработчики пытаются решить эту проблему «в лоб», удаляя ненужные строки из итогового документа перед сохранением. Для этого используется метод УдалитьОбласть() со смещением ячеек. Пример такого кода:
Смещать = ТипСмещенияТабличногоДокумента.ПоВертикали;
Область = ТабДок.Область("R1C1:R8C56"); // Удаляем первые 8 строк макета
ТабДок.УдалитьОбласть(Область, Смещать);
Несмотря на то, что визуально задача кажется решенной, данный подход крайне не рекомендуется к использованию на практике по следующим причинам:
.xls или .xlsx в конце файла часто образуются невидимые пустые строки с неопределенным форматированием. Внешние парсеры и автоматические системы импорта данных (например, портал ЕГИССО) считывают эти строки как пустые записи с ошибками заполнения и отклоняют весь файл целиком.УдалитьОбласть с высокой долей вероятности вызовет ошибку времени выполнения или непредсказуемо исказит ширину колонок во всем документе.R1C1:R8C56) станут неверными, и программа начнет удалять полезные данные клиентов.Единственным архитектурно верным и надежным решением является строгое разделение макета-шаблона и результирующего документа-приемника. Рассмотрим этот алгоритм пошагово:
Посмотрим на практический пример реализации этого алгоритма:
&НаСервере
Процедура ВыгрузитьНаСервере()
// Получаем объект и макет-источник
Об = РеквизитФормыВЗначение("Объект");
МакетИсточник = Об.ПолучитьМакет("Макет");
// Создаем абсолютно чистый результирующий документ
ТабДокДляЗаписи = Новый ТабличныйДокумент;
// Получаем область строки параметров из макета
ОбластьСтроки = МакетИсточник.ПолучитьОбласть("Строки");
// Заполняем результирующий документ в цикле
Для Каждого Стр Из Объект.СписокЛюдей Цикл
// Заполняем параметры области
ОбластьСтроки.Параметры.Контрагент = Стр.Контрагент;
ОбластьСтроки.Параметры.Сумма = Стр.Сумма;
// Выводим заполненную область в чистый документ
ТабДокДляЗаписи.Вывести(ОбластьСтроки);
КонецЦикла;
// Безопасная запись на диск с обработкой исключений
ПутьКФайлу = "C:\" + Объект.Организация + "_" + Формат(Объект.Дата, "ДЛФ=ДД") + ".xlsx";
Попытка
ТабДокДляЗаписи.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.XLSX);
Сообщить("Выгрузка успешно завершена! Файл сохранен: " + ПутьКФайлу);
Исключение
ЗаписьЖурналаРегистрации("Выгрузка в Excel", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
ВызватьИсключение "Не удалось записать файл Excel. Обратитесь к администратору. Причина: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;
КонецПроцедуры
В данном коде мы полностью исключили появление старых статических надписей макета в готовом файле. Итоговый документ будет содержать исключительно те строки, которые мы вывели программно в цикле обработки.
Чтобы ваша выгрузка работала быстро, надежно и не вызывала сбоев на сервере, рекомендуем придерживаться нескольких профессиональных правил разработки в среде 1С:Предприятие 8.3.
В старых примерах кода часто можно встретить использование формата ТипФайлаТабличногоДокумента.XLS. Это формат Excel 97-2003, который имеет ряд критических ограничений:
Использование ТипФайлаТабличногоДокумента.XLSX снимает ограничение по строкам (до 1 048 576 строк на лист), существенно ускоряет процесс генерации файла на стороне платформы 1С и уменьшает итоговый вес файла за счет современного сжатия zip-контейнера.
Если перед вами стоит задача выгрузить абсолютно «чистые» сырые данные (без рамок, специфических шрифтов и раскраски ячеек), то создавать макет в конфигураторе вообще не имеет смысла. Это избыточная работа, которая к тому же уязвима к человеческому фактору (любой другой разработчик может случайно отредактировать макет и сломать выгрузку).
Заполнить ячейки табличного документа можно напрямую по координатам. Рассмотрим пример такой выгрузки:
ТабДок = Новый ТабличныйДокумент;
НомерСтроки = 1;
Для Каждого Стр Из Объект.СписокЛюдей Цикл
// Заполняем первую колонку (Контрагент)
ТабДок.Область(НомерСтроки, 1).Текст = Строка(Стр.Контрагент);
// Заполняем вторую колонку (Сумма)
ТабДок.Область(НомерСтроки, 2).Текст = Строка(Стр.Сумма);
НомерСтроки = НомерСтроки + 1;
КонецЦикла;
ТабДок.Записать("C:\ЧистаяВыгрузка.xlsx", ТипФайлаТабличногоДокумента.XLSX);
Этот способ гарантирует максимальное быстродействие и полную чистоту результирующего Excel-файла без малейшего риска появления пустых областей или некорректно смещенных ячеек.
Если ваши данные уже выведены на форму в виде таблицы или находятся в объекте типа ТаблицаЗначений, платформа 1С предоставляет мощный штатный механизм быстрого построения отчетов — метод ВывестиСписок(). Он позволяет выгрузить всю таблицу в табличный документ буквально одной строкой кода:
ТабДок = Новый ТабличныйДокумент;
// Выводим только элементы строк без оформления дерева и иерархии
ТабДок.ВывестиСписок(Объект.СписокЛюдей.Выгрузить());
ТабДок.Записать("C:\БыстраяВыгрузка.xlsx", ТипФайлаТабличногоДокумента.XLSX);
При частых выгрузках больших массивов данных (десятки тысяч строк) сервер 1С (процесс rphost) может испытывать повышенную нагрузку на оперативную память. Табличные документы являются «тяжелыми» объектами. Чтобы избежать утечек памяти, перед уничтожением локальных переменных в коде рекомендуется явно очищать табличный документ методом ТабДок.Очистить(). Это помогает сборщику мусора платформы 1С оперативно освобождать ресурсы сервера.