При интеграции 1С с внешними базами данных (например, Oracle) через ADO, программисты часто сталкиваются с тем, что данные из полей типа BLOB приходят в виде объекта COMSafeArray. Если внутри этого массива содержатся текстовые данные в определенной кодировке (например, Windows-1251), простая попытка приведения к строке или использование функции Символ() не даст желаемого результата. Мы получим либо набор цифр (кодов байтов), либо «кракозябры» из-за несовпадения кодировок (1С использует Unicode).
В этой статье мы подробно разберем, как правильно обработать такие данные в оперативной памяти, избегая медленных операций с диском, и выясним, почему полученный массив может «исчезать» прямо во время отладки.
Если вы работаете на современной версии платформы, задача решается максимально элегантно. Разработчики 1С добавили специальные инструменты для бесшовной конвертации данных между COM и внутренними типами платформы. Рассмотрим этот процесс по шагам.
Для начала нам необходимо перевести «чужеродный» COMSafeArray в родной для 1С тип ДвоичныеДанные. Для этого используется метод глобального контекста ПолучитьДвоичныеДанныеИзCOMSafeArray(). После этого мы можем применить метод преобразования в строку с указанием нужной кодировки.
Пример кода:
// Предположим, РезультатЗапроса - это поле, содержащее BLOB
МассивБайт = РезультатЗапроса.Fields("MyBlobColumn").Value;
Если ТипЗнч(МассивБайт) = Тип("COMSafeArray") Тогда
// 1. Извлекаем данные из COM в объект 1С
ДвоичныеДанные = ПолучитьДвоичныеДанныеИзCOMSafeArray(МассивБайт);
// 2. Преобразуем двоичные данные в строку, указывая Windows-1251
// Платформа сама позаботится о перекодировании в UTF-16 (внутренний формат 1С)
ЧитаемаяСтрока = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанные, "windows-1251");
Сообщить(ЧитаемаяСтрока);
КонецЕсли;
Этот метод является наиболее производительным, так как выполняется на уровне движка платформы без лишних COM-вызовов и промежуточных объектов.
Если ваша конфигурация работает на более старых версиях платформы или вам требуется большая гибкость в манипуляциях с потоками данных, мы можем воспользоваться объектом ADODB.Stream. Этот объект Windows выступает в роли интеллектуального буфера в оперативной памяти.
Разберем логику работы: мы записываем «сырые» байты в поток как бинарную информацию, а затем «просим» поток отдать нам эти же данные, но уже как текст, предварительно указав кодировку.
Пошаговая реализация:
ADODB.Stream.Type в значение 1 (adTypeBinary).Open().COMSafeArray в поток методом Write().Position = 0).adTypeText).Charset (в нашем случае "windows-1251").ReadText().Пример реализации на языке 1С:
Stream = Новый COMОбъект("ADODB.Stream");
Stream.Type = 1; // Бинарный режим
Stream.Open();
Stream.Write(МассивБайт); // МассивБайт - это ваш COMSafeArray
Stream.Position = 0; // Возврат к началу
Stream.Type = 2; // Переключение в текстовый режим
Stream.Charset = "windows-1251"; // Установка кодировки источника
РезультатТекст = Stream.ReadText();
Stream.Close();
Сообщить(РезультатТекст);
Проанализируем ситуацию, описанную многими разработчиками: при попытке посмотреть значение переменной в табло отладчика или при повторном обращении к объекту, COMSafeArray внезапно принимает значение NULL или становится пустым. Выясним причину этого странного поведения.
Дело в том, что при работе с BLOB через интерфейс ADO, данные часто передаются не как готовый массив, целиком лежащий в памяти, а как последовательный поток (Stream). Когда вы обращаетесь к свойству Value, COM-объект начинает чтение этого потока.
Важные нюансы:
Value дважды. Сразу присваивайте результат локальной переменной: Данные = Поле.Value; и работайте только с этой переменной. Избегайте просмотра таких объектов в отладчике до момента их обработки.Иногда лучшим решением в 1С будет отсутствие необходимости что-либо преобразовывать. Мы можем попросить СУБД Oracle подготовить данные заранее. Вместо того чтобы тянуть «сырые» байты (RAW/BLOB), можно использовать функции пакета UTL_I18N.
Рассмотрим пример SQL-запроса, который можно отправить из 1С:
SELECT UTL_I18N.RAW_TO_CHAR(MY_BLOB_COLUMN, 'CL8MSWIN1251') AS STRING_DATA
FROM MY_TABLE
В этом случае 1С получит в качестве результата обычную строку, и вам не придется возиться с COMSafeArray и его конвертацией. Это значительно упрощает код на стороне 1С и снижает нагрузку на COM-соединение.
Часто новички пытаются использовать цикл Для каждого или перебор индексов с использованием функции Символ(). Проанализируем, почему это плохая практика:
Символ(Код) в 1С ожидает код символа в кодировке Unicode. В кодировке Windows-1251 русская буква "А" имеет код 192. Однако в Unicode код 192 соответствует символу "À" (латиница с грависом). В итоге вы получите нечитаемый текст.Строка = Строка + Символ(Код)) в 1С работает крайне медленно из-за особенностей выделения памяти под строки. Для больших объемов данных это может занять минуты.Резюме: Если вы столкнулись с COMSafeArray, содержащим текст, используйте ПолучитьСтрокуИзДвоичныхДанных для новых версий 1С или ADODB.Stream для совместимости со старыми системами. Это гарантирует правильную работу с кодировками и высокую скорость обработки данных.