При интеграции систем 1С с интернет-магазинами, мобильными приложениями или внешними базами данных поставщиков одной из ключевых задач становится автоматизация импорта медиаконтента. Наполнение базы номенклатуры изображениями вручную — процесс трудоемкий, поэтому разработчики часто прибегают к программной загрузке. В современных конфигурациях фирмы 1С, таких как Управление торговлей 11, Комплексная автоматизация 2.0 и ERP Управление предприятием, архитектура хранения присоединенных файлов претерпела значительные изменения по сравнению с ранними версиями платформ.
В этой статье мы подробно разберем эволюцию подходов к загрузке картинок номенклатуры: от прямого создания элементов в СУБД до использования современных стандартов Библиотеки стандартных подсистем (БСП). Мы также проанализируем частые ошибки разработчиков, такие как проблемы с записью файлов при включенном хранении в томах на диске и блокировки реквизитов формы.
Начиная с БСП версий 2.x/3.x, крайне не рекомендуется вручную создавать элементы справочников присоединенных файлов и напрямую модифицировать связанные с ними регистры сведений. Логика современных конфигураций завязана на сложные механизмы транзакций, кэширования, проверок прав доступа и ведения истории изменений. Для корректной и безопасной загрузки файлов в систему используются экспортные методы БСП. Для изучения доступных процедур и функций библиотеки пригодится справочник по методам БСП с примерами кода.
Разберем готовый рабочий алгоритм пакетного добавления картинок из локальной папки. Процесс разделяется на клиентскую и серверную части для оптимизации трафика и производительности.
На клиенте мы получаем файлы, помещаем их во временное хранилище и передаем адреса на сервер:
&НаКлиенте
Процедура ЗагрузитьКартинкиНоменклатуры(Команда)
// Путь к папке, где лежат изображения (например, "C:\Images\")
Если Не ЗначениеЗаполнено(ПутьКПапкеКартинок) Тогда
ВызватьИсключение "Укажите путь к каталогу с изображениями!";
КонецЕсли;
// Ищем файлы с расширением JPG в указанном каталоге
МассивФайлов = НайтиФайлы(ПутьКПапкеКартинок, "*.jpg", Ложь);
Для Каждого ТекущийФайл Из МассивФайлов Цикл
// Помещаем двоичные данные файла во временное хранилище
АдресВременногоХранилища = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ТекущийФайл.ПолноеИмя), Новый УникальныйИдентификатор);
// Передаем данные на сервер для обработки и привязки к номенклатуре
// Имя файла без расширения используется в качестве кода или артикула для поиска товара
ПоместитьКартинкуНаСервере(ТекущийФайл.ИмяБезРасширения, ТекущийФайл.Расширение, ТекущийФайл.ПолучитьУниверсальноеВремяИзменения(), АдресВременногоХранилища);
КонецЦикла;
КонецПроцедуры
На сервере мы находим номенклатуру по ключевому реквизиту (например, артикулу или коду), подготавливаем структуру параметров для БСП и вызываем метод добавления файла:
&НаСервере
Процедура ПоместитьКартинкуНаСервере(ИмяФайла, РасширениеФайла, ВремяИзмененияУниверсальное, АдресВременногоХранилища)
// Ищем номенклатуру-владельца будущего файла по артикулу
ТоварСсылка = Справочники.Номенклатура.НайтиПоРеквизиту("Артикул", ИмяФайла);
// Если товар найден и у него еще нет установленной картинки
Если ЗначениеЗаполнено(ТоварСсылка) И Не ЗначениеЗаполнено(ТоварСсылка.ФайлКартинки) Тогда
// Подготавливаем параметры создания присоединенного файла согласно БСП
ПараметрыФайла = Новый Структура;
ПараметрыФайла.Вставить("ВладелецФайлов", ТоварСсылка);
ПараметрыФайла.Вставить("ИмяБезРасширения", ИмяФайла);
ПараметрыФайла.Вставить("РасширениеБезТочки", СтрЗаменить(РасширениеФайла, ".", ""));
ПараметрыФайла.Вставить("Автор", Пользователи.ТекущийПользователь());
ПараметрыФайла.Вставить("ВремяИзмененияУниверсальное", ВремяИзмененияУниверсальное);
// Добавляем файл через стандартный общий модуль БСП
// Функция сама определит место хранения (ИБ или тома на диске), создаст карточку и заполнит регистры
ПрисоединенныйФайлСсылка = ПрисоединенныеФайлы.ДобавитьПрисоединенныйФайл(ПараметрыФайла, АдресВременногоХранилища);
// Если файл успешно создан, привязываем его в качестве основного изображения номенклатуры
Если ЗначениеЗаполнено(ПрисоединенныйФайлСсылка) Тогда
НоменклатураОбъект = ТоварСсылка.ПолучитьОбъект();
НоменклатураОбъект.ФайлКартинки = ПрисоединенныйФайлСсылка;
НоменклатураОбъект.Записать();
КонецЕсли;
Иначе
// Очищаем временное хранилище, если файл не был востребован
УдалитьИзВременногоХранилища(АдресВременногоХранилища);
EndIf;
КонецПроцедуры
В более старых версиях конфигураций, где интеграция с БСП еще не была столь глубокой, или в самописных конфигурациях, разработчикам приходилось вручную инициализировать элементы справочников хранения файлов и регистров. Рассмотрим, как решить эту задачу "вручную" при загрузке картинки напрямую с веб-сервера по HTTP-протоколу.
Выясним логику процесса: сначала скачивается файл, создается двоичный объект, создается запись в справочнике НоменклатураПрисоединенныеФайлы, данные записываются в служебный регистр сведений ПрисоединенныеФайлы, а затем ссылка записывается в реквизит номенклатуры.
Процедура ЗагрузитьКартинкуНапрямуюССайта(НоменклатураОбъект, ИмяКартинкиНаСайте)
КартинкаСсылка = Справочники.НоменклатураПрисоединенныеФайлы.ПустаяСсылка();
// Задаем параметры HTTP-соединения с сайтом-источником
Соединение = Новый HTTPСоединение("адрес_сайта_поставщика.ru");
ИмяВременногоФайла = ПолучитьИмяВременногоФайла(".jpg");
Попытка
// Скачиваем файл во временный каталог на диске сервера/клиента
Соединение.Получить("/images/" + ИмяКартинкиНаСайте, ИмяВременногоФайла);
Исключение
ЗаписьЖурналаРегистрации("ЗагрузкаКартинок", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
Возврат;
КонецПопытки;
// Создаем элемент справочника присоединенных файлов
КартинкаОбъект = Справочники.НоменклатураПрисоединенныеФайлы.СоздатьЭлемент();
КартинкаОбъект.ТипХраненияФайла = Перечисления.ТипыХраненияФайлов.ВИнформационнойБазе;
КартинкаОбъект.Наименование = НоменклатураОбъект.Код;
КартинкаОбъект.ВладелецФайла = НоменклатураОбъект.Ссылка;
КартинкаОбъект.Расширение = "jpg";
КартинкаОбъект.СтатусИзвлеченияТекста = Перечисления.СтатусыИзвлеченияТекстаФайлов.НеИзвлечен;
// Читаем скачанный файл в объект Картинка и получаем двоичные данные для ХранилищаЗначения
К1 = Новый Картинка(ИмяВременногоФайла, Истина);
КартинкаОбъект.ФайлХранилище = Новый ХранилищеЗначения(К1.ПолучитьДвоичныеДанные());
ФайлК = Новый Файл(ИмяВременногоФайла);
КартинкаОбъект.Размер = ФайлК.Размер;
// Записываем карточку файла в базу данных, чтобы получить ссылку
КартинкаОбъект.Записать();
КартинкаСсылка = КартинкаОбъект.Ссылка;
// Заполняем служебный регистр сведений "ПрисоединенныеФайлы", без этого платформа выдаст ошибку
КартинкаСохранить = РегистрыСведений.ПрисоединенныеФайлы.СоздатьНаборЗаписей();
КартинкаСохранить.Отбор.ПрисоединенныйФайл.Установить(КартинкаСсылка);
НовыйФайл = КартинкаСохранить.Добавить();
НовыйФайл.ПрисоединенныйФайл = КартинкаСсылка;
НовыйФайл.ХранимыйФайл = КартинкаОбъект.ФайлХранилище;
// Записываем набор записей регистра
КартинкаСохранить.Записать();
// Связываем файл с номенклатурой
НоменклатураОбъект.ФайлКартинки = КартинкаСсылка;
НоменклатураОбъект.Записать();
// Удаляем временный файл с диска
УдалитьФайлы(ИмяВременногоФайла);
КонецПроцедуры
Рассмотрим детально частые проблемы, с которыми сталкиваются программисты 1С при внедрении подобных решений, и разберем способы их устранения.
Выясним причину этой ошибки. Часто начинающие разработчики пытаются внедрить код загрузки прямо в форму элемента номенклатуры и пишут конструкцию вида Объект.ФайлКартинки = СсылкаНаФайл на клиенте. В управляемых формах реквизит Объект является типом ДанныеФормыСтруктура, и некоторые его поля могут быть аппаратно заблокированы от интерактивного изменения бизнес-логикой формы.
Решение: Всю логику работы с объектами СУБД (создание файлов, изменение реквизитов номенклатуры) необходимо выполнять строго на сервере в контексте объектной модели (получив реальный СправочникОбъект через метод ПолучитьОбъект()). Также рекомендуется выносить тяжелые процедуры загрузки во внешние обработки, чтобы изолировать их от контекста открытых форм.
Невозможно привязать присоединенный файл к номенклатуре, которая еще не существует в базе физически. У незаписанного элемента значение Номенклатура.Ссылка является пустым, а значит, поле ВладелецФайла у присоединенного файла заполнить не удастся.
Решение: Сначала выполните метод Записать() для новой номенклатуры, получите ссылку на элемент базы данных и только после этого инициализируйте параметры добавления изображения.
Если в настройках программы включено хранение присоединенных файлов в томах на диске, ручной код (Метод 2) продолжит принудительно записывать бинарные данные непосредственно в СУБД (в реквизит ФайлХранилище), раздувая базу данных. При этом на сетевом диске файлы создаваться не будут.
Решение: Использование БСП-метода ПрисоединенныеФайлы.ДобавитьПрисоединенныйФайл() полностью решает эту проблему. Алгоритмы БСП сами анализируют константы настроек системы. Если включено дисковое хранение, библиотека автоматически извлечет файл из временного хранилища, переименует его по уникальному GUID, запишет в физический сетевой каталог тома и сформирует правильные относительные пути в карточке файла информационной базы.
Массовая загрузка файлов поставщиков "как есть" часто приводит к быстрому расходу дискового пространства. Фотографии высокого разрешения (например, 4000x3000 пикселей) не нужны для карточек товаров. Перед загрузкой рекомендуется выполнять конвертацию или программное сжатие.
Платформа 1С поддерживает встроенный метод Картинка.Преобразовать(), с помощью которого можно изменить формат тяжелых картинок в сжатый JPEG:
ИсходнаяКартинка = Новый Картинка(ПутьКФайлу);
Если ИсходнаяКартинка.Формат() <> ФорматКартинки.JPEG Тогда
КонвертированнаяКартинка = ИсходнаяКартинка.Преобразовать(ФорматКартинки.JPEG);
ДвоичныеДанныеДляСохранения = КонвертированнаяКартинка.ПолучитьДвоичныеДанные();
КонецЕсли;
Применяя данные подходы и используя стандарты БСП, вы сможете построить отказоустойчивую и быструю систему программной синхронизации каталога товаров с любыми внешними источниками, сохранив целостность данных 1С и оптимальный объем информационной базы. Для предотвращения раздувания базы данных подойдёт инструмент для сжатия изображений в конфигурациях на БСП.