Как ускорить очень долгое заполнение таблицы шаблона Word в клиент-серверной 1С?

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

Коллеги, сегодня мы рассмотрим весьма актуальную проблему, с которой часто сталкиваются разработчики 1С: очень долгое заполнение таблиц в шаблонах Word при использовании COM-объекта Word.Application в клиент-серверной конфигурации. Разберем, почему возникает эта задержка, и предложим современные, высокопроизводительные решения, которые позволят значительно сократить время формирования документов.

Автор нашей темы столкнулся с тем, что формирование печатной формы с заполнением таблицы в MS Word, реализованное через Внешнюю Печатную Форму (ВПФ), занимает неприемлемо много времени (до 40 минут для 67 строк) в клиент-серверном режиме, тогда как в файловой версии операция выполняется практически мгновенно. Мы проанализируем корневые причины такого поведения и представим пути решения.

В чем заключается проблема медленного заполнения таблицы Word через COM в клиент-серверной 1С?

Давайте сначала выясним, почему мы наблюдаем такую существенную разницу в производительности между файловой и клиент-серверной версиями 1С при работе с COM-объектом Word. Изначальный код, вызывающий проблему, выглядит следующим образом:


&НаКлиенте
Процедура Печать_ПриказОПремировании(СтруктураДок)    
    
    Word = Новый COMОбъект("Word.Application"); 
    ИмяМакета="ЗаРезультатыГодовая";    
    
    Макет = ПолучитьМакетСервер(ИмяМакета);
    // макет в формате ДД
    ИмяФайла_Макет = ПолучитьИмяВременногоФайла("docx");
    Макет.Записать(ИмяФайла_Макет);
    ДокументWord = Word.Documents.ADD(ИмяФайла_Макет);
    ДокументWord.Activate();    
    
    СоздатьИЗаполнитьТЗПодстановок_ПриказОПремировании(СтруктураДок);    
    
    Для Каждого СтрТЗ Из Объект.ПромТЗ Цикл
        ПоискИЗаменаВWord_НаКлиенте(ДокументWord,СтрТЗ.Шаблон,СтрТЗ.СтрокаЗначения);        
    КонецЦикла;    
    
    Таб = ДокументWord.Tables.Item(2); 
    
    Для Сч = 1 По Объект.ПромТЗТаблица.Количество() Цикл
        Таб.Rows.Add(Таб.Rows(2));
    КонецЦикла;    
    
    Строка=2;
    
    Для Каждого СтрТЗ Из Объект.ПромТЗТаблица Цикл 
        
        ДанныеСтроки=СтрТЗ;
        
        //ВОТ ТУТ НАЧИНАЮТСЯ ТОРМОЗА В КЛИЕНТ-СЕРВЕРНОЙ ВЕРСИИ....
        // --->
            Таб.Cell(Строка,1).Range().InsertAfter(СтрТЗ.Подразделение); 
            Таб.Cell(Строка,2).Range().InsertAfter(СтрТЗ.Сотрудник);    
            Таб.Cell(Строка,3).Range().InsertAfter(СтрТЗ.Должность); 
            Таб.Cell(Строка,4).Range().InsertAfter(СтрТЗ.Премия); 
        // <----        
        Строка = Строка + 1;    
        
    КонецЦикла; 
    
    Таб.Rows(Строка).Delete();
    
    Word.Visible = Истина; 
    Word.Application.WindowState  = 2;//свернуть
    Word.Application.WindowState  = 1;//развернуть    
    Word.Activate();    
    
КонецПроцедуры

Главная причина замедления в клиент-серверном режиме заключается в способе взаимодействия с COM-объектом Word:

  1. Передача данных через сеть: При работе в клиент-серверном режиме, если код, управляющий COM-объектом Word, выполняется на клиенте (как в нашем случае, процедура &НаКлиенте), то все операции с объектом Word.Application, который физически запускается на клиентской машине, приводят к многочисленным сетевым вызовам. Каждое обращение к свойству или методу Word, например, Таб.Cell(Строка,1).Range().InsertAfter(), инициирует отдельный запрос по сети. При заполнении таблицы с большим количеством строк и ячеек это приводит к тысячам мелких сетевых пакетов, что катастрофически замедляет процесс. В файловом режиме все происходит локально на одном компьютере, поэтому задержек нет.
  2. "Тяжеловесность" COM-объекта Word: Объект Word.Application предназначен для интерактивной работы пользователя. Программное управление им через COM, особенно выполнение большого числа мелких операций (построчное заполнение ячеек таблицы), не является оптимизированным для высокой производительности. Word выполняет множество внутренних операций, связанных с обработкой документа, его рендерингом и форматированием, даже если окно приложения невидимо.
  3. Потенциальные побочные эффекты: Использование COM-объекта Word на клиенте для фонового формирования документов может приводить к непредвиденным последствиям. Например, если пользователь во время формирования документа скопирует что-либо в буфер обмена (Ctrl+C), этот текст может быть вставлен в формируемый документ Word, поскольку COM-объект может взаимодействовать с системным буфером обмена. Это может стать причиной серьезных ошибок и недоразумений.

Таким образом, основной "затык" происходит именно в цикле построчного заполнения ячеек таблицы, где каждое обращение к Таб.Cell(...).Range().InsertAfter() генерирует отдельное, медленное взаимодействие по сети.

Решение проблемы: Переход на работу с OpenXML через БСП

Наиболее эффективным и современным решением данной проблемы является отказ от прямого использования COM-объекта Word на клиенте и переход к формированию документов на стороне сервера 1С с использованием механизмов работы с файлами формата OpenXML (.docx), предоставляемых Библиотекой Стандартных Подсистем (БСП).

Мы рассмотрим этот подход подробнее:

  1. Использование серверных механизмов 1С и OpenXML

    Вместо того чтобы запускать приложение Word на клиентской машине и управлять им через COM, мы можем формировать документ Word напрямую на сервере 1С. Современные файлы Word (.docx) по своей сути являются ZIP-архивами, содержащими набор XML-файлов, описывающих структуру и содержимое документа. Работая напрямую с этими XML-файлами, мы можем создавать и модифицировать документы значительно быстрее, так как нет необходимости запускать полноценное приложение Word.

    Этот подход позволяет избежать всех проблем, связанных с сетевыми задержками и "тяжеловесностью" COM-объекта, поскольку вся работа по формированию документа происходит на сервере, где 1С-серверный процесс имеет прямой доступ к файлам и не требует взаимодействия с пользовательским интерфейсом.

  2. Функциональность БСП для работы с документами Word (OpenXML)

    Библиотека Стандартных Подсистем (БСП) в 1С:Предприятии предоставляет готовую функциональность для работы с внешними печатными формами и шаблонами документов, которая зачастую реализована именно через механизмы OpenXML. Это значительно упрощает разработку, поскольку не требуется писать низкоуровневый код для манипуляции XML-файлами.

    При использовании БСП мы обычно работаем с шаблонами, в которых определены специальные области и поля для заполнения. В отличие от COM-объектов, где мы вставляем текст по ячейкам, механизмы БСП позволяют "раскручивать" области шаблона для таблиц или списков, передавая туда целые коллекции данных. Это значительно сокращает количество операций и, следовательно, время выполнения.

    Наш автор темы подтвердил эффективность этого подхода, столкнувшись с первоначальными трудностями, но успешно освоив его. Он отметил, что настройка для существующих сложных макетов может быть трудоемкой на первом этапе, но при создании макетов с нуля или после освоения механизма, работа значительно ускоряется и становится более удобной.

    Разберем основные принципы работы с таким подходом на примере, основанном на обсуждении в теме:

    1. Подготовка шаблона Word: Мы создаем шаблон .docx, в котором определяем специальные области и поля для заполнения. Например, для списка или таблицы мы можем использовать синтаксис вида {v8 Область.ИмяОбласти} для обозначения повторяющихся блоков и {v8 Поле} для отдельных значений.

      Пример структуры макета для списка, как показано в обсуждении:

      
      {v8 Область.СписокУровень1}
      1.    {v8 ТекстСписок1}
      {/v8 Область.СписокУровень1}
      

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

    2. Формирование данных в 1С: Мы готовим данные в 1С в виде структур или таблиц значений. Эти данные будут переданы серверному механизму БСП для заполнения шаблона.
    3. Вызов серверного метода БСП: На клиенте мы вызываем серверную процедуру, которая использует функциональность БСП. Эта процедура принимает шаблон и данные, формирует документ на сервере и возвращает готовый файл клиенту.
    4. Динамическое форматирование: Как показал автор темы, даже для сложного форматирования внутри одной строки списка или ячейки таблицы можно использовать несколько полей-заполнителей.

      Например, чтобы покрасить часть текста или подчеркнуть его:

      
      {v8 Область.СписокУровень1}
      1.    {v8 ТекстСписок1Часть}    {v8 ТекстСписок1Часть_ЭтуКрасимЦветом}..... {v8 ТекстСписок1Часть_ЭтуПодчеркиваем}
      {/v8 Область.СписокУровень1}
      

      В этом случае мы передаем в каждое поле соответствующую часть текста, а в шаблоне Word заранее настраиваем форматирование для этих полей (например, задаем красный цвет для ТекстСписок1Часть_ЭтуКрасимЦветом и подчеркивание для ТекстСписок1Часть_ЭтуПодчеркиваем). Механизм БСП сохранит это форматирование при заполнении.

    Таким образом, мы видим, что решение с использованием БСП и OpenXML является не только более производительным, но и более гибким и безопасным по сравнению с прямым COM-взаимодействием.

Общие рекомендации по оптимизации при работе с COM-объектом Word (менее эффективные, но иногда полезные)

Если по каким-либо причинам вы все же вынуждены использовать COM-объект Word на клиенте, существуют некоторые общие рекомендации, которые могут немного улучшить производительность, хотя они не решают проблему сетевых задержек кардинально:

  1. Отключение отображения Word: Всегда устанавливайте Word.Visible = Ложь до начала операций и делайте его видимым только в самом конце, если это необходимо. Это предотвращает ненужную перерисовку интерфейса, которая потребляет ресурсы. Однако, как мы выяснили, даже при невидимом окне Word может выполнять внутренние процессы, потребляющие время.

    Пример:

    
    Word.Visible = Ложь; // Отключаем видимость
    // ... все операции с Word ...
    Word.Visible = Истина; // Включаем видимость в конце
    
  2. Отключение обновления экрана и проверки орфографии: В некоторых случаях может помочь временное отключение обновления экрана и проверки орфографии/грамматики в Word.

    Пример:

    
    Word.Application.ScreenUpdating = Ложь;
    Word.Application.Options.CheckSpellingAsYouType = Ложь;
    Word.Application.Options.CheckGrammarAsYouType = Ложь;
    // ... операции ...
    Word.Application.ScreenUpdating = Истина;
    Word.Application.Options.CheckSpellingAsYouType = Истина;
    Word.Application.Options.CheckGrammarAsYouType = Истина;
    

    Важно не забыть включить эти опции обратно после завершения операций.

  3. Оптимизация шаблона Word: Избегайте в шаблоне сложных макросов, большого количества стилей, связанных полей или других элементов, которые могут замедлять внутреннюю обработку документа самим Word. Чем проще структура шаблона, тем быстрее он обрабатывается.
  4. Вставка таблиц целиком: Вместо заполнения каждой ячейки по отдельности в цикле, рассмотрите возможность формирования данных для таблицы (например, в виде HTML-фрагмента или текстовой строки с разделителями) и последующей вставки их в документ Word одним вызовом. Это значительно уменьшит количество обращений к COM-объекту.

    Например, можно сформировать HTML-код таблицы в строке 1С и затем вставить его в закладку Word:

    
    // Предполагается, что данныеСформированыВHTML уже содержит полноценный HTML-код таблицы
    // ДокументWord.Bookmarks("МояЗакладкаДляТаблицы").Range.InsertHtml(ДанныеСформированыВHTML);
    

    Однако этот подход требует определенных навыков работы с HTML и может быть не всегда применим.

Заключение

Мы проанализировали проблему медленного заполнения таблиц Word через COM-объект в клиент-серверной 1С и пришли к выводу, что наиболее эффективным и надежным решением является переход на современные механизмы работы с документами OpenXML через Библиотеку Стандартных Подсистем. Этот подход позволяет значительно увеличить скорость формирования документов за счет серверной обработки и прямого манипулирования XML-структурой файла, минуя "тяжеловесный" COM-объект Word.

Хотя начальное внедрение может показаться трудоемким, в долгосрочной перспективе это решение окупается стабильностью, производительностью и гибкостью, что было подтверждено нашим автором темы.

← На главную