При интеграции систем часто возникает необходимость выгрузить графические файлы (фотографии товаров, скан-копии документов, штрихкоды) из информационной базы 1С напрямую во внешнюю базу данных MySQL. В MySQL для хранения бинарных данных большого объема традиционно используется тип LONGBLOB. Однако при попытке записать файл в таблицу разработчики часто сталкиваются с ситуацией, когда запрос выполняется без явных синтаксических ошибок, но данные в поле не обновляются.
Разберем подробно, почему популярный способ с функцией LOAD_FILE() может не работать, а также рассмотрим надежные альтернативные варианты прямой передачи двоичных данных из кода 1С.
Один из первых способов, который пробуют разработчики — вызвать встроенную функцию MySQL:
UPDATE photo SET HIRES_RASTER = LOAD_FILE("D:\Новая папка\1.jpg") WHERE id = 514;
В результате СУБД возвращает статус Rows matched: 1 Changed: 0, а в поле записывается NULL. Проанализируем ключевые причины такого поведения:
\ является спецсимволом экранирования. Строка вида "D:\Новая папка\1.jpg" воспринимается парсером как символы \N и \1. Путь необходимо указывать либо с прямыми слэшами: "D:/Новая папка/1.jpg", либо удваивать обратные слэши: "D:\\Новая папка\\1.jpg".LOAD_FILE() выполняется строго на стороне сервера СУБД и ищет файл в локальной файловой системе машины, где установлен MySQL. Если служба MySQL запущена на отдельном сервере или в Docker-контейнере, путь D:\Новая папка\1.jpg на клиентском компьютере или сервере 1С для нее просто не существует.NULL, импорт файлов через LOAD_FILE() полностью заблокирован. Если там указан путь (например, папка Uploads), файл обязан лежать именно внутри нее. Проверить настройку можно командой: SHOW VARIABLES LIKE 'secure_file_priv';.FILE.max_allowed_packet, функция возвратит NULL.Ввиду этих ограничений передача файла через LOAD_FILE() создает сильную зависимость от файловой системы сервера MySQL. Поэтому предпочтительнее передавать бинарное содержимое файла непосредственно из контекста 1С.
Рассмотрим наиболее универсальный и надежный подход. Мы считываем файл на стороне 1С в объект ДвоичныеДанные, переводим его в шестнадцатеричную строку и передаем в SQL-запрос. В MySQL для восстановления исходного бинарного вида применяется встроенная функция UNHEX() или шестнадцатеричный литерал 0x.
Посмотрим на пример кода на платформе 1С:
ПутьКФайлу = "D:/Новая папка/1.jpg";
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
СтрокаHex = ПолучитьHexСтрокуИзДвоичныхДанных(ДвоичныеДанныеФайла);
ИДЗаписи = 514;
ТекстЗапроса = "UPDATE photo SET HIRES_RASTER = UNHEX('" + СтрокаHex + "') WHERE id = " + Формат(ИДЗаписи, "ЧГ=0") + ";";
// Выполняем полученный ТекстЗапроса через установленное соединение с СУБД
Обратите внимание: также допустимо передавать данные через префикс шестнадцатеричного литерала: SET HIRES_RASTER = 0x.... Однако при использовании функции UNHEX() синтаксис остается более наглядным при сборке параметризованных запросов.
Еще один распространенный способ — кодирование файла в строку стандарта Base64. Начиная с версии MySQL 5.6.1, в СУБД доступна встроенная функция FROM_BASE64(), преобразующая закодированный текст обратно в бинарный блоб.
Разберем по шагам реализацию этого механизма:
ПутьКФайлу = "D:/Новая папка/1.jpg";
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
СтрокаBase64 = Base64Строка(ДвоичныеДанныеФайла);
ИДЗаписи = 514;
ТекстЗапроса = "UPDATE photo SET HIRES_RASTER = FROM_BASE64('" + СтрокаBase64 + "') WHERE id = " + Формат(ИДЗаписи, "ЧГ=0") + ";";
Сравним Base64 и HEX: при кодировании в Base64 размер текста запроса возрастает примерно на 33%, тогда как HEX удваивает объем данных (каждый байт кодируется двумя символами). Однако Base64 требует более современной версии MySQL.
Если сервер 1С работает под управлением Windows и подключение к MySQL осуществляется через COM-технологию ADODB.Connection, можно передавать данные напрямую в бинарном виде через параметры команды, не перегружая строку SQL длинными строковыми литералами.
Проанализируем пример выполнения параметризованного запроса:
// Создаем поток и загружаем в него бинарный файл
Поток = Новый COMОбъект("ADODB.Stream");
Поток.Type = 1; // adTypeBinary
Поток.Open();
Поток.LoadFromFile("D:\Новая папка\1.jpg");
// Настраиваем команду ADODB
Команда = Новый COMОбъект("ADODB.Command");
Команда.ActiveConnection = СоединениеMySQL; // Открытый ADODB.Connection
Команда.CommandText = "UPDATE photo SET HIRES_RASTER = ? WHERE id = ?;";
// Создаем параметр для BLOB-поля (adLongVarBinary = 205, adParamInput = 1)
РазмерДанных = Поток.Size;
ПараметрДанные = Команда.CreateParameter("p_raster", 205, 1, РазмерДанных, Поток.Read());
Команда.Parameters.Append(ПараметрДанные);
// Создаем параметр для идентификатора (adInteger = 3, adParamInput = 1)
ПараметрИД = Команда.CreateParameter("p_id", 3, 1, , 514);
Команда.Parameters.Append(ПараметрИД);
// Выполняем команду
Команда.Execute();
Поток.Close();
Важное ограничение: данный способ задействует COM-объекты Windows. Если сервер 1С функционирует на базе Linux, COM-соединения будут недоступны. Для кроссплатформенных сред рекомендуется использовать прямую генерацию HEX/Base64 запросов, либо передавать файлы во внешний сервис через объект HTTPСоединение.
При передаче файлов любого типа через SQL-запросы обязательно проверьте параметр max_allowed_packet в конфигурационном файле MySQL (my.ini или my.cnf). По умолчанию он может быть равен 4 или 16 мегабайтам. Если передаваемый файл (с учетом накладных расходов кодирования HEX или Base64) превысит этот лимит, СУБД сбросит сетевое соединение с ошибкой Packet too large.
Для стабильной загрузки изображений высокого разрешения рекомендуется задать значение параметра с запасом, например:
max_allowed_packet = 64M
После внесения изменений в файл конфигурации необходимо перезапустить службу MySQL.