Как загрузить файл из 1С в базу данных MS SQL Server?

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

В процессе работы с 1С часто возникает задача интеграции со сторонними системами. Одна из таких задач — выгрузка файлов, сформированных в 1С (например, печатных форм отчетов в формате PDF), в базу данных на MS SQL Server. Напрямую передать двоичные данные не всегда очевидно, особенно при работе через COM-объект ADODB.Connection. Рассмотрим один из способов решения этой задачи, его особенности, а также разберем более универсальные и производительные альтернативы.

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

Способ 1: Загрузка через преобразование в HEX-строку

Основная идея этого метода — прочитать файл в двоичные данные, преобразовать их в текстовое представление (шестнадцатеричную строку) и вставить эту строку прямо в текст SQL-запроса. На стороне SQL Server эта строка будет обратно преобразована в двоичный формат и сохранена в поле типа VARBINARY(MAX).

Давайте разберем по шагам, как это реализовать.

  1. Формирование и сохранение файла. Сначала необходимо сформировать нужный нам файл. В примере это табличный документ, который сохраняется в формате PDF во временный каталог.
  2. Подключение к MS SQL Server. Для взаимодействия с базой данных используется стандартный COM-объект ADODB.Connection. Мы настраиваем строку подключения, указывая драйвер, сервер, базу данных и учетные данные.
  3. Чтение файла и преобразование. Сохраненный файл считывается в объект ДвоичныеДанные. Затем, с помощью стандартной функции 1С ПолучитьHexСтрокуИзДвоичныхДанных(), эти данные конвертируются в длинную текстовую строку.
  4. Формирование и выполнение SQL-запроса. Самый важный этап: мы формируем текстовую строку SQL-запроса INSERT. В эту строку мы подставляем метаданные файла (имя, идентификаторы) и саму HEX-строку. Для того чтобы SQL Server понял, что это шестнадцатеричное представление двоичных данных, мы используем функцию CONVERT(varbinary(max), @hexstring, 2). Третий параметр `2` как раз и указывает на то, что исходная строка не содержит префикса `0x`.

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


// Предполагается, что переменные ИмяСервераSQL, ПользовательSQL, 
// ПарольSQL, БазаДанныхSQL, Клиент, ТабличныйДокумент уже определены.

Если ТабличныйДокумент.ВысотаТаблицы = 0 Тогда
    // Если отчет пуст, формируем его
    СформироватьОтчет("Расш"); 
КонецЕсли;

/////////////////////////////////////////
// Подключение к SQL-серверу
Соединение = Новый COMОбъект("ADODB.Connection");
Команда = Новый COMОбъект("ADODB.Command");
Выборка = Новый COMОбъект("ADODB.RecordSet");

Соединение.ConnectionString = "driver={SQL Server};" + 
                           "server=" + ИмяСервераSQL + ";" + 
                           "uid=" + ПользовательSQL + ";" + 
                           "pwd=" + ПарольSQL + ";" + 
                           "database=" + БазаДанныхSQL + ";";

Соединение.ConnectionTimeout = 30;
Соединение.CommandTimeout = 600;

// Открытие соединение
Соединение.Open();
Команда.ActiveConnection = Соединение;

// Сохраняем табличный документ во временный файл
ИмяФайла = КаталогВременныхФайлов() + "Отчет.pdf";
ТабличныйДокумент.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.PDF);

Попытка
    // Читаем файл в двоичные данные
    ДД = Новый ДвоичныеДанные(ИмяФайла);
Исключение
    Соединение.Close();
    Возврат;
КонецПопытки;

Если ДД.Размер() = 0 Тогда
    Соединение.Close();
    Возврат;
КонецЕсли;

// Формируем SQL-запрос с HEX-строкой
ТекстКоманды = "
|DECLARE @hexstring varchar(max);
|SET @hexstring = '" + ПолучитьHexСтрокуИзДвоичныхДанных(ДД) + "';
|INSERT INTO ClientFiles 
|    (UID, CLIENT_UID, NAME, CONTENT) 
|VALUES 
|    ('" + Новый УникальныйИдентификатор() + "', '" + Клиент + "', 'Отчет.pdf', CONVERT(varbinary(max), @hexstring, 2))
|";

Команда.CommandText = ТекстКоманды;
Команда.Execute;

// Закрываем соединение
Соединение.Close();

Анализ метода: когда его стоит применять?

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

Преимущества:

Недостатки:

Вывод: данный способ отлично подходит для своей узкой задачи — загрузки очень маленьких файлов. Автор оригинального сообщения указал, что его файлы были размером около 36 КИЛОБАЙТ. Для таких объемов все перечисленные недостатки не являются критичными, и простота кода оправдывает его использование. Если вы уверены, что ваши файлы никогда не превысят нескольких сотен килобайт, это решение может быть для вас приемлемым.

Способ 2: Использование параметризованных запросов и ADODB.Stream

Для более универсальных и надежных решений рекомендуется использовать параметризованные запросы. Это не только безопаснее (защищает от SQL-инъекций), но и позволяет передавать двоичные данные напрямую, без неэффективных преобразований в текст. Для корректной работы с файлами мы будем использовать объект ADODB.Stream.

Алгоритм действий:

  1. Создаем и настраиваем `ADODB.Stream`. Этот объект специально предназначен для работы с потоками данных, в том числе с файлами.
  2. Загружаем файл в поток. Используем метод Stream.LoadFromFile().
  3. Готовим команду с параметрами. В тексте SQL-запроса на месте, где должны быть двоичные данные, ставим знак параметра (обычно `?`).
  4. Создаем и добавляем параметр. С помощью метода Command.CreateParameter() создаем объект параметра. Очень важно указать правильный тип данных — adLongVarBinary (числовой код 205), который предназначен для больших двоичных объектов.
  5. Передаем данные в параметр. Значением параметра будет содержимое нашего потока, которое мы получаем методом Stream.Read().
  6. Выполняем команду.

Этот подход является промышленным стандартом для работы с BLOB-объектами (Binary Large Object) и лишен недостатков предыдущего метода. Он эффективно работает с файлами любого размера, ограниченного только возможностями SQL Server (до 2 ГБ для `VARBINARY(MAX)`).

Способ 3: Порционная загрузка с AppendChunk для очень больших файлов

Если вам предстоит работать с файлами огромного размера (десятки и сотни мегабайт), даже второй способ может создать большую нагрузку на сеть и память, так как весь файл читается в память целиком. Для таких случаев в ADO существует механизм порционной загрузки — AppendChunk.

Общая идея:

  1. Открывается объект ADODB.Recordset для целевой таблицы.
  2. Добавляется новая пустая запись методом Recordset.AddNew().
  3. Исходный файл (или поток данных) читается не целиком, а небольшими порциями (чанками), например, по 64 КБ.
  4. Каждая порция данных дописывается в нужное поле записи с помощью метода Поле.AppendChunk(ПорцияДанных).
  5. После того как все порции записаны, изменения сохраняются методом Recordset.Update().

Этот метод самый сложный в реализации, но и самый щадящий по отношению к системным ресурсам. Он гарантирует, что даже при загрузке гигабайтных файлов потребление оперативной памяти будет минимальным.

Итог

Рассмотрев три разных подхода, можно сделать следующие выводы:

Выбор конкретного метода всегда зависит от требований вашей задачи, предполагаемого размера файлов и требований к производительности и надежности системы.

← На главную