При интеграции 1С с внешними базами данных через механизм Внешние источники данных программисты часто сталкиваются с проблемой корректного чтения бинарных данных. Особую сложность представляют случаи, когда во внешней базе (например, в архиве или копии системы) хранятся данные, которые изначально были записаны платформой 1С в поле типа ХранилищеЗначения. В SQL-сервере такие данные обычно имеют тип varbinary(max).
Проблема заключается в том, что прямое чтение такого поля через Внешний источник данных возвращает объект типа ДвоичныеДанные. Если мы попытаемся просто обернуть их в новое хранилище, платформа не сможет «распознать» внутреннюю структуру данных (например, Структуру или ТаблицуЗначений), которая там находилась. Рассмотрим подробно, почему это происходит и как правильно восстановить исходные объекты.
Разберем типичную ошибку. Часто разработчики пытаются использовать следующий код:
// Ошибочный подход
ДвДанныеИзSQL = СтрокаВнешнегоИсточника.ДанныеХранилища; // Тип ДвоичныеДанные
НовоеХранилище = Новый ХранилищеЗначения(ДвДанныеИзSQL, Новый СжатиеДанных(9));
МояСтруктура = НовоеХранилище.Получить(); // Вернет ДвоичныеДанные, а не Структуру
Проанализируем ситуацию: платформа 1С при записи объекта в ХранилищеЗначения добавляет к нему специальные технические заголовки, содержащие информацию о типе данных и способе сжатия. Когда мы считываем это поле из SQL напрямую, мы получаем «сырой» массив байтов вместе с этими заголовками. Создавая новое хранилище конструктором Новый ХранилищеЗначения, мы просто упаковываем этот массив байтов еще раз. В итоге метод Получить() честно возвращает нам то, что мы положили — массив байтов, не пытаясь его десериализовать в исходный объект.
Самым эффективным способом заставить платформу интерпретировать набор байтов как полноценный объект ХранилищеЗначения является использование механизмов XML-сериализации. Этот метод «обманывает» систему, заставляя её выполнить глубокую десериализацию. Рассмотрим пример кода:
// Функция преобразования двоичных данных в ХранилищеЗначения
Функция ПолучитьХранилищеИзДвоичныхДанных(ДвДанные)
// Шаг 1: Сериализуем ДвоичныеДанные в XML-обертку
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
ЗаписатьXML(ЗаписьXML, ДвДанные);
СтрокаСериализации = ЗаписьXML.Закрыть();
// Шаг 2: Читаем полученный XML как ХранилищеЗначения
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(СтрокаСериализации);
// Используем СериализаторXDTO для восстановления типа
Результат = СериализаторXDTO.ПрочитатьXML(ЧтениеXML, Тип("ХранилищеЗначения"));
Возврат Результат;
КонецФункции
Выясним причину, почему это работает. Метод ЗаписатьXML для типа ДвоичныеДанные создает стандартное строковое представление. Однако при обратном чтении через СериализаторXDTO с явным указанием типа ХранилищеЗначения, платформа распознает внутренние заголовки 1С в бинарном потоке и автоматически восстанавливает исходный объект (структуру, массив и т.д.).
Существует более компактный вариант решения той же задачи, который часто применяется в однострочных выражениях. Разберем его по шагам:
ДвДанные = СтрокаВнешнегоИсточника.ПолеBinary;
Хранилище = XMLЗначение(Тип("ХранилищеЗначения"), ПолучитьBase64СтрокуИзДвоичныхДанных(ДвДанные));
Объект = Хранилище.Получить();
В данном случае мы вручную переводим бинарные данные в строку Base64 и передаем ее функции XMLЗначение. Платформа понимает, что данная строка является сериализованным хранилищем, и восстанавливает его содержимое.
Посмотрим на специфику конкретной конфигурации. В «1С:Документообороте» версии объектов хранятся в регистре сведений ВерсииОбъектов. Реквизит ВерсияОбъекта имеет тип ХранилищеЗначения, но внутри него находится не просто XML, а Структура.
Проанализируем состав этой структуры:
Если вы просто восстановите хранилище, вы получите эту структуру. Для дальнейшей работы с самим текстом версии (XML) вам может потребоваться распаковать FastInfoset. В современных версиях БСП для этого рекомендуется использовать функции общего модуля ВерсионированиеОбъектов, например, метод РазвернутьДанныеВерсии.
При работе с большими объемами данных через Внешние источники данных (ВИД) следует учитывать несколько технических моментов:
1. Ограничения драйвера ODBC. При чтении полей varbinary(max) большого объема драйвер может обрезать данные или возвращать ошибку. Убедитесь, что используете актуальную версию SQL Server Native Client.
2. Сжатие данных. Платформа 1С при записи в ХранилищеЗначения часто использует алгоритм Deflate. Если вы получили данные из SQL и они кажутся «нечитаемыми», возможно, они уже сжаты. При создании нового хранилища вручную (если вы решите не использовать методы XML) важно не устанавливать флаг сжатия повторно, иначе вы получите двойную упаковку, которую 1С не сможет открыть штатно.
3. Производительность. Метод с XML-сериализацией (Способ №1) требует выделения памяти под строку XML, что при работе с очень большими версиями файлов (например, многомегабайтные PDF в версиях ДО) может привести к существенному потреблению ресурсов сервера. В таких случаях рассмотрим возможность использования COM-объекта ADODB.Stream для прямой манипуляции потоками байтов без преобразования в Base64.
Для успешного восстановления данных из SQL обратно в 1С необходимо помнить, что поле varbinary(max) — это не просто содержимое файла, а сериализованный объект 1С. Чтобы «вернуть его к жизни», используйте СериализаторXDTO или функцию XMLЗначение. Это позволит вам корректно восстановить типизацию данных, будь то сложная структура версии объекта или простая таблица значений.