Как перенести данные из ХранилищаЗначения в другую базу через V83COMConnector?

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

При интеграции нескольких информационных баз 1С часто возникает задача переноса файлов и бинарных данных (картинок, документов PDF, архивов), которые хранятся в реквизитах с типом ХранилищеЗначения. При попытке сделать это "в лоб" через COM-соединение (V83COMConnector) разработчики сталкиваются с проблемой: прямое присвоение вида БазаПриемник.Хранилище = БазаИсточник.Хранилище не работает.

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

Причина проблемы и особенности COM-маршаллинга

При обращении к внешней базе данных через COM-соединение все возвращаемые объекты непримитивных типов передаются на вызывающую сторону не в виде готовых объектов 1С, а в виде прокси-объектов с типом COMОбъект.

Когда мы вызываем метод Получить() у COM-объекта ХранилищеЗначения, вызывающая программа получает не нативный объект ДвоичныеДанные, а его COM-обертку. Локальный конструктор Новый ХранилищеЗначения() на стороне приемника ожидает на входе только стандартные типы данных 1С, поддерживающие сериализацию. Переданный в него COMОбъект не распознается системой, из-за чего в базу записывается пустое значение или возникает ошибка выполнения.

Для решения этой проблемы необходимо передать данные в таком формате, который COM-соединение сможет корректно маршаллизовать (передать между процессами без потери структуры). Ниже приведены три надежных способа реализации этой задачи.

Способ 1. Передача через Base64-строку (Решение автора темы)

Строковый тип данных является примитивным и без проблем передается через COM-соединение. Мы можем преобразовать двоичные данные в строку формата Base64 на стороне одной базы, передать эту строку по COM и восстановить двоичные данные на стороне другой базы.

Рассмотрим по шагам, как это реализовать, если перенос инициирован со стороны базы-источника (База 2) в базу-приемник (База 1):

  1. Извлекаем двоичные данные из хранилища источника.
  2. Конвертируем их в Base64-строку с помощью функции Base64Строка().
  3. Передаем строку в базу-приемник по COM-соединению.
  4. На стороне приемника преобразуем строку обратно в двоичные данные с помощью COM-метода Base64Значение().
  5. Создаем новое хранилище значения в приемнике через метод NewObject().

Посмотрим на практический пример кода:


// 1. Получаем двоичные данные из хранилища в базе-источнике
ДвоичныеДанныеИсточника = ВыборкаДетальныеЗаписи.Хранилище.Получить();

// 2. Кодируем двоичные данные в Base64-строку
ДвоичныеСтрокой = Base64Строка(ДвоичныеДанныеИсточника);

// Предположим, что База1 — это наше активное COM-соединение с базой-приемником
// 3. Преобразуем Base64-строку в объект ДвоичныеДанные на стороне приемника
ОлеФайл = База1.Base64Значение(ДвоичныеСтрокой);

// 4. Помещаем полученный объект в новое ХранилищеЗначения базы-приемника
// Используем метод NewObject для создания объекта ХранилищеЗначения в контексте Базы 1
СпрОбъектПриемник = База1.Справочники.Номенклатура.НайтиПоКоду("00001").ПолучитьОбъект();
СпрОбъектПриемник.Хранилище = База1.NewObject("ХранилищеЗначения", ОлеФайл, База1.NewObject("СжатиеДанных"));
СпрОбъектПриемник.Записать();

Способ 2. Прямая XML-сериализация объекта

Объект типа ХранилищеЗначения по умолчанию поддерживает XML-сериализацию. Платформа 1С при сериализации автоматически кодирует бинарное содержимое хранилища в Base64. Это позволяет передать объект целиком в виде XML-текста, минуя ручное извлечение двоичных данных.

Проанализируем этот элегантный способ:


// На стороне источника (База 2) сериализуем ХранилищеЗначения в строку XML
СтрокаXML = COMСоединение.XMLСтрока(РезЗапросаБаза2.Хранилище);

// На стороне приемника (База 1) десериализуем XML-строку обратно в объект ХранилищеЗначения
База1.Хранилище = XMLЗначение(Тип("ХранилищеЗначения"), СтрокаXML);

Этот метод значительно сокращает количество строк кода и исключает ошибки ручного преобразования типов.

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

Если объем передаваемых файлов очень велик (сотни мегабайт или гигабайты), передача файлов "в памяти" через Base64 может привести к перерасходу оперативной памяти на сервере и аварийному завершению рабочих процессов 1С. В таких случаях надежнее использовать промежуточную выгрузку на диск.

Разберем алгоритм этого метода:

  1. На стороне источника получаем двоичные данные из хранилища и записываем их на жесткий диск в общий сетевой каталог: ДвоичныеДанные.Записать(ПутьКФайлу).
  2. Передаем в базу-приемник по COM-соединению только текстовый путь к файлу.
  3. На стороне приемника создаем объект ДвоичныеДанные, считывая файл с диска: Новый ДвоичныеДанные(ПутьКФайлу).
  4. Помещаем эти данные в реквизит и записываем объект.
  5. Удаляем временный файл с диска.

Альтернатива: Переход на HTTP-сервисы

Важно помнить, что технология COM-соединения (V83COMConnector) считается устаревшей и имеет ряд серьезных ограничений: она работает только под управлением ОС Windows, требует обязательной регистрации Windows-библиотеки comcntr.dll и крайне чувствительна к несовпадению версий платформы клиента и сервера.

Для надежного обмена бинарными данными в современных конфигурациях рекомендуется использовать HTTP-сервисы. Передача файлов напрямую в теле POST-запроса (например, с использованием заголовка Content-Type: application/octet-stream) работает быстрее, стабильнее, не нагружает оперативную память процесса COM и полностью независима от операционной системы и версий платформы 1С.

← На главную