Как преобразовать COMSafeArray в читаемую строку 1С без использования временных файлов

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

При интеграции 1С с внешними базами данных (например, Oracle) через ADO, программисты часто сталкиваются с тем, что данные из полей типа BLOB приходят в виде объекта COMSafeArray. Если внутри этого массива содержатся текстовые данные в определенной кодировке (например, Windows-1251), простая попытка приведения к строке или использование функции Символ() не даст желаемого результата. Мы получим либо набор цифр (кодов байтов), либо «кракозябры» из-за несовпадения кодировок (1С использует Unicode).

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

Способ 1. Использование встроенных методов 1С (Платформа 8.3.10 и выше)

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

Для начала нам необходимо перевести «чужеродный» COMSafeArray в родной для 1С тип ДвоичныеДанные. Для этого используется метод глобального контекста ПолучитьДвоичныеДанныеИзCOMSafeArray(). После этого мы можем применить метод преобразования в строку с указанием нужной кодировки.

Пример кода:


// Предположим, РезультатЗапроса - это поле, содержащее BLOB
МассивБайт = РезультатЗапроса.Fields("MyBlobColumn").Value;

Если ТипЗнч(МассивБайт) = Тип("COMSafeArray") Тогда
    // 1. Извлекаем данные из COM в объект 1С
    ДвоичныеДанные = ПолучитьДвоичныеДанныеИзCOMSafeArray(МассивБайт);
    
    // 2. Преобразуем двоичные данные в строку, указывая Windows-1251
    // Платформа сама позаботится о перекодировании в UTF-16 (внутренний формат 1С)
    ЧитаемаяСтрока = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанные, "windows-1251");
    
    Сообщить(ЧитаемаяСтрока);
КонецЕсли;

Этот метод является наиболее производительным, так как выполняется на уровне движка платформы без лишних COM-вызовов и промежуточных объектов.

Способ 2. Использование ADODB.Stream (Универсальный метод)

Если ваша конфигурация работает на более старых версиях платформы или вам требуется большая гибкость в манипуляциях с потоками данных, мы можем воспользоваться объектом ADODB.Stream. Этот объект Windows выступает в роли интеллектуального буфера в оперативной памяти.

Разберем логику работы: мы записываем «сырые» байты в поток как бинарную информацию, а затем «просим» поток отдать нам эти же данные, но уже как текст, предварительно указав кодировку.

Пошаговая реализация:

  1. Создаем COM-объект ADODB.Stream.
  2. Устанавливаем свойство Type в значение 1 (adTypeBinary).
  3. Открываем поток методом Open().
  4. Записываем наш COMSafeArray в поток методом Write().
  5. Сбрасываем позицию указателя в начало (Position = 0).
  6. Меняем тип потока на 2 (adTypeText).
  7. Указываем кодировку через свойство Charset (в нашем случае "windows-1251").
  8. Считываем текстовое представление методом 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 «исчезает» в отладчике?

Проанализируем ситуацию, описанную многими разработчиками: при попытке посмотреть значение переменной в табло отладчика или при повторном обращении к объекту, COMSafeArray внезапно принимает значение NULL или становится пустым. Выясним причину этого странного поведения.

Дело в том, что при работе с BLOB через интерфейс ADO, данные часто передаются не как готовый массив, целиком лежащий в памяти, а как последовательный поток (Stream). Когда вы обращаетесь к свойству Value, COM-объект начинает чтение этого потока.

Важные нюансы:

Способ 3. Преобразование на стороне сервера базы данных

Иногда лучшим решением в 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. Проблема кодировок: Функция Символ(Код) в 1С ожидает код символа в кодировке Unicode. В кодировке Windows-1251 русская буква "А" имеет код 192. Однако в Unicode код 192 соответствует символу "À" (латиница с грависом). В итоге вы получите нечитаемый текст.
  2. Производительность: Посимвольная сборка длинной строки в цикле (Строка = Строка + Символ(Код)) в 1С работает крайне медленно из-за особенностей выделения памяти под строки. Для больших объемов данных это может занять минуты.

Резюме: Если вы столкнулись с COMSafeArray, содержащим текст, используйте ПолучитьСтрокуИзДвоичныхДанных для новых версий 1С или ADODB.Stream для совместимости со старыми системами. Это гарантирует правильную работу с кодировками и высокую скорость обработки данных.

← На главную