Как скопировать табличный документ в 1С с сохранением параметров и областей?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке отчетов и печатных форм в среде «1С:Предприятие 8» программисты часто сталкиваются с необходимостью создать точную копию существующего табличного документа (объекта типа ТабличныйДокумент). Это может потребоваться для программного изменения макета перед выводом пользователю, формирования сложных составных отчетов или кэширования печатных форм.

Однако стандартный и интуитивно понятный метод Вывести() не решает задачу полностью. При его использовании копируются только ячейки и их текстовое содержимое, но теряются важные свойства структуры: именованные области, рисунки, настройки печати (поля, ориентация, масштаб) и, что самое критичное, коллекция параметров областей (Параметры). Метод ЗаполнитьЗначенияСвойств() для параметров также оказывается бесполезным, поскольку коллекция параметров в новом документе изначально пуста, а методы прямого добавления элементов в нее отсутствуют.

В этой статье мы подробно разберем, почему возникает эта проблема, и рассмотрим несколько эффективных и надежных способов ее решения — от простых файловых методов до современных платформенных механизмов сериализации и готовых функций БСП (Библиотеки Стандартных Подсистем).

Выясняем причину: почему не работает простое копирование?

Когда мы пытаемся скопировать табличный документ «в лоб», используя следующий код:


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

Мы сталкиваемся с тем, что структура параметров в целевом документе МакетПечатнойФормыИзм не создается. Объект ПараметрыМакетаТабличногоДокумента является системной коллекцией. Платформа 1С генерирует параметры динамически на основе разметки ячеек (когда у ячейки свойство «Заполнение» установлено в значение «Параметр» или «Шаблон»). Без физического переноса метаструктуры областей коллекция параметров остается пустой, и заполнить её значениями из источника невозможно.

Давайте разберем рабочие и надежные обходные пути.

Способ 1. Клонирование через Временное хранилище (Самый простой платформенный метод)

Если вам необходимо получить абсолютно независимую, идентичную «глубокую» копию табличного документа на сервере, самым элегантным и быстрым способом является сериализация через временное хранилище платформы. Этот метод не задействует дисковую подсистему и работает полностью в оперативной памяти.

Проанализируем пример кода:


// Помещаем исходный документ во временное хранилище
АдресХранилища = ПоместитьВоВременноеХранилище(МакетПечатнойФормы);

// Извлекаем его обратно — платформа создает абсолютно новый, чистый объект-клон
МакетПечатнойФормыИзм = ПолучитьИзВременногоХранилища(АдресХранилища);

Преимущества метода:

  1. Минимум строк кода.
  2. Абсолютная точность копирования: переносятся все области, параметры, картинки, расшифровки и настройки страниц.
  3. Высокая скорость работы за счет отсутствия обращений к жесткому диску.

Способ 2. Использование потоков в памяти (Для платформы 1С v8.3.9 и выше)

Начиная с версии платформы 8.3.9, разработчикам стал доступен объект ПотокВПамяти. Этот механизм позволяет сериализовать табличный документ в бинарный поток формата MXL в оперативной памяти компьютера без создания физических файлов на диске.

Рассмотрим, как реализовать этот подход по шагам:


// Создаем поток в оперативной памяти
Поток = Новый ПотокВПамяти();

// Записываем исходный табличный документ в поток в системном формате MXL
МакетПечатнойФормы.Записать(Поток, ТипФайлаТабличногоДокумента.MXL);

// Сбрасываем позицию чтения потока на начало
Поток.Перейти(0, ПозицияВПотоке.Начало);

// Создаем новый пустой табличный документ
МакетПечатнойФормыИзм = Новый ТабличныйДокумент();

// Читаем данные из потока в новый документ
МакетПечатнойФормыИзм.Прочитать(Поток);

// Закрываем поток для освобождения памяти
Поток.Закрыть();

Этот способ является наиболее технологичным и производительным при работе в многопоточных серверных сценариях, так как он полностью изолирован от ограничений прав доступа к файловой системе сервера.

Способ 3. Копирование через временный файл на диске

Если вы работаете на старых версиях платформы 1С, где объект ПотокВПамяти еще не поддерживается, можно прибегнуть к классическому способу сохранения документа во временный файл формата MXL с последующим чтением.

Посмотрим на пример реализации:


// Получаем уникальное имя временного файла в системе
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("mxl");

// Сохраняем исходный макет на диск
МакетПечатнойФормы.Записать(ИмяВременногоФайла);

// Инициализируем новый документ и считываем файл
МакетПечатнойФормыИзм = Новый ТабличныйДокумент;
МакетПечатнойФормыИзм.Прочитать(ИмяВременногоФайла);

// Обязательно удаляем временный файл с диска после завершения операции
Попытка
    УдалитьФайлы(ИмяВременногоФайла);
Исключение
    // Запись в журнал регистрации в случае блокировки файла операционной системой
    ЗаписьЖурналаРегистрации("КопированиеТабДок", УровеньЖурналаРегистрации.Предупреждение,,, "Не удалось удалить временный файл: " + ИмяВременногоФайла);
КонецПопытки;

Важное примечание: При использовании этого метода на сервере убедитесь, что у учетной записи, под которой запущен рабочий процесс службы rphost, есть права на запись и удаление файлов в системной директории временных файлов.

Способ 4. Стандартные функции БСП (Библиотеки Стандартных Подсистем)

Если ваша конфигурация построена на базе БСП, вам не обязательно писать собственный код для копирования. Разработчики БСП уже предусмотрели готовые процедуры общего назначения, которые учитывают все нюансы платформы. Для разработки печатных решений по стандартам подсистем можно использовать пример реализации внешней печатной формы на актуальной версии БСП.

Для копирования структуры и свойств документов можно использовать следующие методы:


СвойстваДляКопирования = УправлениеПечатью.КопируемыеСвойстваТабличногоДокумента();
ЗаполнитьЗначенияСвойств(МакетПечатнойФормыИзм, МакетПечатнойФормы, СвойстваДляКопирования);

Способ 5. Использование метода платформы ВставитьОбласть()

Если перед вами стоит задача скопировать не весь документ целиком, а перенести определенный фрагмент (диапазон ячеек) с сохранением параметров, используйте метод ВставитьОбласть() вместо Вывести().

Этот метод специально разработан для копирования структурированных областей ячеек из одного табличного документа в другой с сохранением структуры параметров:


// Определяем область-источник
ОбластьИсточник = МакетПечатнойФормы.Область(1, 1, МакетПечатнойФормы.ВысотаТаблицы, МакетПечатнойФормы.ШиринаТаблицы);

// Определяем начальную ячейку-приемник в новом документе
ОбластьПриемник = МакетПечатнойФормыИзм.Область("R1C1");

// Выполняем вставку области с сохранением параметров
МакетПечатнойФормыИзм.ВставитьОбласть(ОбластьИсточник, ОбластьПриемник, ТипСмещенияТабличногоДокумента.ПоВертикали, Истина);

Параметр Истина в конце метода отвечает за перенос параметров и расшифровок ячеек в целевой документ, что решает изначальную проблему нехватки параметров.

Резюме и рекомендации

Выбор оптимального метода зависит от архитектуры вашего решения и требований к производительности:

  1. Для полного и быстрого клонирования документа на сервере лучше всего использовать метод сериализации через Временное хранилище (Способ 1) или Поток в памяти (Способ 2). Это современные, безопасные и наиболее производительные варианты.
  2. Если вы работаете в рамках типовых конфигураций 1С, всегда проверяйте наличие готовых функций в общем модуле УправлениеПечатью (Способ 4).
  3. Для выборочного переноса табличных блоков с сохранением структуры параметров используйте метод ВставитьОбласть() (Способ 5).
← На главную