Как записать файл из 1С в поле типа image или varbinary внешней базы SQL?

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

При интеграции 1С с внешними системами (например, Service Desk, CRM или ERP сторонних разработчиков) нередко возникает необходимость передавать прикрепленные файлы напрямую в таблицы Microsoft SQL Server. Часто в таких таблицах для хранения файлов используются типы данных image или varbinary(max).

Попытка передать файл через обычную конкатенацию строк в динамическом SQL-запросе приводит к ошибкам синтаксиса либо к тому, что в базу сохраняется не сам бинарный файл, а его строковое представление. Разберем причины возникновения этих ошибок и рассмотрим надежные способы передачи бинарных данных из 1С во внешнюю СУБД.

Почему возникает ошибка при простой вставке через строку запроса

Проанализируем ситуацию: если мы получаем файл в виде объекта ДвоичныеДанные и пытаемся вставить его в текст запроса через оператор +, платформа 1С неявно преобразует двоичные данные в шестнадцатеричную строку с пробелами между байтами (например, "22 49 44 22 3B...").

  1. Передача значения без кавычек: наличие пробелов в строке шестнадцатеричных кодов приводит к синтаксической ошибке на стороне SQL Server (Incorrect syntax near ' ').
  2. Передача значения в одинарных кавычках: SQL Server интерпретирует строку как обычный текст varchar. При сохранении в поле image или varbinary сохраняется именно текст строки, а не исходное содержимое файла, из-за чего сохраненный файл оказывается поврежденным.
  3. Форматирование чисел: приведение чисел к строке в 1С по умолчанию содержит неразрывные пробелы в группах разрядов (например, "6 768"), что также ломает SQL-синтаксис при динамической склейке запросов. Для чисел всегда необходимо использовать функцию Формат(Число, "ЧГ=0").

Рассмотрим правильные способы передачи двоичных данных.

Способ 1. Параметризованный запрос через ADODB.Command и ADODB.Stream

Наиболее надежный и безопасный способ передачи бинарных данных через COM-соединение — использование параметров команды ADODB.Command совместно с объектом потока ADODB.Stream. Поток позволяет прочитать файл как массив байтов (SafeArray) и передать его в бинарный параметр без строковых преобразований.

Разберем по шагам реализацию этого способа:


// 1. Считываем файл в бинарный поток ADO
Поток = Новый COMОбъект("ADODB.Stream");
Поток.Type = 1; // 1 = adTypeBinary
Поток.Open();
Поток.LoadFromFile(ПутьКФайлу);

// 2. Инициализируем команду ADODB
Команда = Новый COMОбъект("ADODB.Command");
Команда.ActiveConnection = АктивноеСоединение;
Команда.CommandType = 1; // 1 = adCmdText
Команда.CommandText = "INSERT INTO [dbo].[tbl_Files] ([ID], [FileData], [FileSize]) VALUES (?, ?, ?)";

// 3. Создаем и добавляем параметры
// adGUID = 72, adParamInput = 1
ПараметрID = Команда.CreateParameter("ID", 72, 1, 16, Строка(ГУИДФайла));
Команда.Parameters.Append(ПараметрID);

// adLongVarBinary = 205
ПараметрФайл = Команда.CreateParameter("FileData", 205, 1, Поток.Size, Поток.Read());
Команда.Parameters.Append(ПараметрФайл);

// adInteger = 3
ПараметрРазмер = Команда.CreateParameter("FileSize", 3, 1, , Поток.Size);
Команда.Parameters.Append(ПараметрРазмер);

// 4. Выполняем запись в базу
Команда.Execute();

Поток.Close();
Поток = Неопределено;
Команда = Неопределено;

Преимущества: исключаются ошибки форматирования, запрос защищен от SQL-инъекций, а план выполнения запроса кэшируется СУБД.

Способ 2. Запись через объект ADODB.Recordset

Если нет необходимости выполнять сложный SQL-запрос, можно использовать объект ADODB.Recordset. Он позволяет добавить новую строку в таблицу напрямую через методы набора записей.

Посмотрим на пример выполнения:


Поток = Новый COMОбъект("ADODB.Stream");
Поток.Type = 1; // adTypeBinary
Поток.Open();
Поток.LoadFromFile(ПутьКФайлу);

НаборЗаписей = Новый COMОбъект("ADODB.Recordset");
// adOpenKeyset = 1, adLockOptimistic = 3
НаборЗаписей.Open("SELECT TOP 0 * FROM [dbo].[tbl_Files]", АктивноеСоединение, 1, 3);

НаборЗаписей.AddNew();
НаборЗаписей.Fields("ID").Value = Строка(ГУИДФайла);
НаборЗаписей.Fields("FileData").Value = Поток.Read();
НаборЗаписей.Fields("FileSize").Value = Поток.Size;
НаборЗаписей.Update();

НаборЗаписей.Close();
Поток.Close();

Способ 3. Формирование шестнадцатеричного литерала SQL

Если требуется выполнить вставку исключительно текстовой SQL-командой без параметров, двоичные данные необходимо подготовить в виде шестнадцатеричного литерала без одинарных кавычек и с префиксом 0x, предварительно очистив строку от пробелов.

Посмотрим, как это выглядит в коде 1С:


ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
СтрокаHex = СтрЗаменить(Строка(ДвоичныеДанныеФайла), " ", "");
РазмерФайла = Формат(ДвоичныеДанныеФайла.Размер(), "ЧГ=0");

ТекстSQL = "INSERT INTO [dbo].[tbl_Files] ([ID], [FileData], [FileSize]) "
         + "VALUES ('" + Строка(ГУИДФайла) + "', 0x" + СтрокаHex + ", " + РазмерФайла + ")";

Команда = Новый COMОбъект("ADODB.Command");
Команда.ActiveConnection = АктивноеСоединение;
Команда.CommandType = 1;
Команда.CommandText = ТекстSQL;
Команда.Execute();

Важно: этот вариант подходит только для небольших файлов. При передаче файлов большого объема длина строки SQL-запроса может превысить допустимые ограничения сетевого пакета или вызвать избыточную нагрузку на память сервера 1С.

Способ 4. Использование внешних источников данных 1С

Платформа 1С:Предприятие 8 предоставляет штатный механизм — Внешние источники данных. С его помощью можно связать внешнюю таблицу SQL Server с конфигурацией через ODBC без использования COM-объектов.

  1. В дереве метаданных конфигурации создаем объект Внешний источник данных и подключаем таблицу tbl_Files.
  2. Поле таблицы типа image или varbinary(max) автоматически маппируется в тип ХранилищеЗначения или ДвоичныеДанные.
  3. Запись в таблицу осуществляется стандартными методами объектной модели 1С:

Менеджер = ВнешниеИсточникиДанных.БазаServiceDesk.Таблицы.tbl_Files.СоздатьМенеджерЗаписи();
Менеджер.ID = Новый УникальныйИдентификатор();
Менеджер.FileData = Новый ДвоичныеДанные(ПутьКФайлу);
Менеджер.FileSize = Новый Файл(ПутьКФайлу).Размер();
Менеджер.Записать();

Ограничения и рекомендации

При настройке обмена обратите внимание на следующие нюансы:

  1. Разрядность компонентов: если сервер 1С работает в 64-битном режиме, на сервере обязательно должны быть установлены 64-битные OLE DB провайдеры или ODBC-драйверы SQL Server.
  2. Тип данных в SQL: тип image в Microsoft SQL Server является устаревшим (deprecated). При наличии возможности модернизировать структуру внешней базы рекомендуется использовать тип varbinary(max).
  3. Права доступа: учетная запись, под которой осуществляется подключение к SQL Server, должна обладать правами INSERT и UPDATE на целевую таблицу базы данных.
← На главную