Как программно загрузить и привязать картинку к товару в 1С

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

При импорте данных о товарах из внешних систем (файлов Excel, XML, JSON или парсеров сайтов) перед разработчиком часто возникает задача автоматической загрузки изображений номенклатуры. В современных конфигурациях 1С, построенных на базе Библиотеки стандартных подсистем (БСП), работа с файлами реализована через специальную подсистему присоединенных файлов. Прямая запись картинок в справочники больше не применяется — вместо этого создается элемент специального подчиненного справочника присоединенных файлов, ссылка на который затем записывается в карточку товара.

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

Основные ошибки при загрузке изображений

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

Ошибка 1. Попытка назначить владельцем файла незаписанный объект (или сам объект вместо ссылки)

В коде БСП при добавлении файла обязательно проверяется реквизит ВладелецФайла. Если вы передаете туда переменную, содержащую тип СправочникОбъект.Номенклатура, система выдаст ошибку о том, что владелец не заполнен. Объекты типа СправочникОбъект существуют только в оперативной памяти сервера до момента их записи. База данных ничего не знает о них, и у них нет уникального идентификатора (ссылки). Чтобы избежать этой ошибки, необходимо строго соблюдать последовательность:

  1. Создать элемент номенклатуры.
  2. Записать элемент в базу данных с помощью метода Записать().
  3. Получить уникальную ссылку НоваяНоменклатура.Ссылка и передать ее в параметры БСП в качестве владельца.

Ошибка 2. Передача пути к файлу вместо двоичных данных во временное хранилище

При использовании функции ПоместитьВоВременноеХранилище() разработчики иногда по ошибке передают в качестве параметра строковый путь к файлу на диске. В результате в хранилище помещается обычная текстовая строка. Когда подсистема БСП пытается прочитать свойства файла, возникает системный сбой: Значение не является значением объектного типа (Размер). БСП ожидает увидеть в хранилище именно объект типа ДвоичныеДанные. Чтобы решить эту проблему, файл сначала нужно преобразовать в двоичный формат:


ДвоичныеДанные = Новый ДвоичныеДанные(ПутьКФайлу);
АдресХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанные);

Ошибка 3. Отсутствие финальной записи объекта номенклатуры

Даже если файл успешно загружен в базу данных и для него создана карточка присоединенного файла, связь не установится автоматически, пока мы не укажем эту связь в самой номенклатуре. Нам необходимо записать полученную ссылку на присоединенный файл в реквизит номенклатуры ФайлКартинки и выполнить повторную запись объекта номенклатуры. В противном случае картинка загрузится в базу "сиротой" и не будет отображаться в карточке товара.

---

Пошаговый разбор правильного алгоритма загрузки

Давайте разберем по шагам логику работы серверной процедуры, которая считывает картинку из локальной папки (или временного каталога) и привязывает ее к конкретному товару.

Шаг 1. Подготовка файла и получение двоичных данных

Сначала мы должны убедиться, что файл физически существует на сервере. После этого считываем его в оперативную память и помещаем во временное хранилище, откуда его сможет забрать программный интерфейс БСП.


ФайлИзображения = Новый Файл(ПутьКФайлу);
Если ФайлИзображения.Существует() Тогда
    ДвоичныеДанные = Новый ДвоичныеДанные(ПутьКФайлу);
    АдресВременногоХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанные);
Иначе
    ВызватьИсключение "Файл изображения не найден по указанному пути!";
КонецЕсли;

Шаг 2. Запись номенклатуры для получения ссылки

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


НовыйТовар = Справочники.Номенклатура.СоздатьЭлемент();
НовыйТовар.Наименование = "Смартфон";
// Заполнение остальных обязательных реквизитов...
НовыйТовар.Записать(); // Теперь у нас есть НовыйТовар.Ссылка!

Шаг 3. Заполнение параметров добавления файла в БСП

В современных версиях БСП ручное конструирование структуры параметров не рекомендуется, так как состав полей может меняться при обновлениях конфигурации. Правильным подходом является вызов стандартного метода РаботаСФайлами.ПараметрыДобавленияФайла(), который возвращает готовую структуру со всеми необходимыми свойствами по умолчанию. Нам остается лишь заполнить ключевые поля:


ПараметрыФайла = РаботаСФайлами.ПараметрыДобавленияФайла();
ПараметрыФайла.ВладелецФайлов = НовыйТовар.Ссылка;
ПараметрыФайла.Автор = Пользователи.ТекущийПользователь();
ПараметрыФайла.ИмяБезРасширения = НовыйТовар.Наименование;
ПараметрыФайла.РасширениеБезТочки = "jpg"; // или "png", в зависимости от исходного файла
ПараметрыФайла.ВремяИзмененияУниверсальное = ТекущаяДатаСеанса();

Шаг 4. Добавление файла в систему и привязка к карточке товара

Вызываем метод БСП РаботаСФайлами.ДобавитьФайл(), который создает элемент справочника присоединенных файлов. Полученную ссылку записываем в карточку нашего товара:


// Добавляем файл в базу данных
СсылкаНаПрисоединенныйФайл = РаботаСФайлами.ДобавитьФайл(ПараметрыФайла, АдресВременногоХранилища);

// Связываем полученный файл с номенклатурой
Если ЗначениеЗаполнено(СсылкаНаПрисоединенныйФайл) Тогда
    НоменклатураОбъект = НовыйТовар.Ссылка.ПолучитьОбъект();
    НоменклатураОбъект.ФайлКартинки = СсылкаНаПрисоединенныйФайл;
    НоменклатураОбъект.Записать();
КонецЕсли;

---

Полный шаблон безопасного кода для интеграции

Ниже представлен готовый к использованию метод, спроектированный с учетом требований стандартов разработки фирмы "1С". Мы добавили обработку исключений, очистку временных ресурсов и проверку на наличие уже существующей картинки у товара (чтобы не плодить дубликаты файлов в базе данных при повторном запуске импорта).


&НаСервере
Процедура ПрограммнаяЗагрузкаКартинкиНоменклатуры(ТоварСсылка, ИмяФайлаИсточника)
    
    // Проверим, заполнен ли товар и записан ли он в базу
    Если Не ЗначениеЗаполнено(ТоварСсылка) Тогда
        ЗаписатьЛогОшибки("Не указан товар для загрузки изображения.");
        Возврат;
    КонецЕсли;
    
    ФайлИзображения = Новый Файл(ИмяФайлаИсточника);
    Если Не ФайлИзображения.Существует() Тогда
        ЗаписатьЛогОшибки("Файл на диске не обнаружен: " + ИмяФайлаИсточника);
        Возврат;
    КонецЕсли;
    
    // Помещаем файл во временное хранилище в виде двоичных данных
    Попытка
        ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ИмяФайлаИсточника);
        АдресХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла);
    Исключение
        ЗаписатьЛогОшибки("Не удалось прочитать двоичные данные файла: " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
    // Начинаем работу с подсистемой БСП
    Попытка
        
        ИмяБезРасширения = ФайлИзображения.ИмяБезРасширения;
        РасширениеБезТочки = СтрЗаменить(ФайлИзображения.Расширение, ".", "");
        
        // Если у товара еще нет привязанной картинки - добавляем новую
        Если ТоварСсылка.ФайлКартинки.Пустая() Тогда
            
            // Используем стандартный инициализатор параметров БСП для обратной совместимости
            ПараметрыФайла = РаботаСФайлами.ПараметрыДобавленияФайла();
            ПараметрыФайла.ВладелецФайлов = ТоварСсылка;
            ПараметрыФайла.Автор = ПараметрыСеанса.ТекущийПользователь;
            ПараметрыФайла.ВремяИзмененияУниверсальное = ТекущаяДата();
            ПараметрыФайла.ИмяБезРасширения = ИмяБезРасширения;
            ПараметрыФайла.РасширениеБезТочки = РасширениеБезТочки;
            
            // Программное создание элемента справочника присоединенных файлов
            НовыйФайлСсылка = РаботаСФайлами.ДобавитьФайл(ПараметрыФайла, АдресХранилища);
            
            // Привязываем созданный файл к реквизиту номенклатуры
            Если ЗначениеЗаполнено(НовыйФайлСсылка) Тогда
                ТоварОбъект = ТоварСсылка.ПолучитьОбъект();
                ТоварОбъект.ФайлКартинки = НовыйФайлСсылка;
                ТоварОбъект.Записать();
                Сообщить("Изображение успешно добавлено для товара: " + ТоварСсылка);
            КонецЕсли;
            
        Иначе // Если картинка уже есть - обновляем существующий файл новой версией двоичных данных
            
            ИнформацияОФайле = Новый Структура;
            ИнформацияОФайле.Вставить("АдресФайлаВоВременномХранилище", АдресХранилища);
            ИнформацияОФайле.Вставить("АдресВременногоХранилищаТекста", "");
            ИнформацияОФайле.Вставить("ИмяБезРасширения", ИмяБезРасширения);
            ИнформацияОФайле.Вставить("ДатаМодификацииУниверсальная", ТекущаяДата());
            ИнформацияОФайле.Вставить("Расширение", РасширениеБезТочки);
            
            РаботаСФайлами.ОбновитьФайл(ТоварСсылка.ФайлКартинки, ИнформацияОФайле);
            Сообщить("Изображение успешно обновлено для товара: " + ТоварСсылка);
            
        КонецЕсли;
        
    Исключение
        ЗаписатьЛогОшибки("Ошибка при работе с подсистемой БСП 'Работа с файлами': " + ОписаниеОшибки());
    КонецПопытки;
    
КонецПроцедуры

Процедура ЗаписатьЛогОшибки(ТекстОшибки)
    // Метод логирования ошибок (запись в Журнал регистрации или вывод пользователю)
    ЗаписьЖурналаРегистрации("ЗагрузкаКартинокНоменклатуры",
                             УровеньЖурналаРегистрации.Ошибка,
                             ,
                             ,
                             ТекстОшибки);
    Сообщить(ТекстОшибки);
КонецПроцедуры

---

Важные рекомендации по оптимизации процесса

При массовой программной загрузке большого количества номенклатуры (от 1000 позиций и более) обратите внимание на следующие нюансы:

  1. Не оборачивайте добавление файлов в транзакции СУБД.

    Если в настройках программы включено хранение присоединенных файлов в томах на диске (внешний сетевой диск), то при вызове метода ДобавитьФайл() физический файл записывается на сетевой диск мгновенно. Если после этого внутри вашей транзакции произойдет ошибка и вызовется метод ОтменитьТранзакцию(), транзакция в SQL откатится (карточка файла исчезнет из базы), но физический файл на диске останется навсегда. Это быстро приведет к замусориванию жесткого диска неиспользуемыми файлами.

  2. Контролируйте очистку временных файлов.

    Если в процессе импорта вы скачиваете картинки из интернета во временную папку сервера с помощью функции ПолучитьИмяВременногоФайла(), обязательно удаляйте их физически с диска сразу после помещения в двоичные данные. Массовая загрузка тысяч картинок может быстро переполнить системный диск сервера 1С.

    
    // Пример безопасного удаления файла после обработки
    Если ФайлИзображения.Существует() Тогда
        Попытка
            УдалитьФайлы(ПутьКВременномуФайлу);
        Исключение
            // Игнорируем ошибку удаления, если файл занят операционной системой
        КонецПопытки;
    КонецЕсли;
    
  3. Скачивание картинок по HTTP/HTTPS ссылкам.

    Если ваши картинки хранятся на веб-сервере, не используйте метод КопироватьФайл() напрямую по сетевому адресу. На сервере 1С под управлением Linux или в условиях работы через прокси-сервер это вызовет ошибку доступа. Правильнее использовать объект HTTPСоединение с защищенным SSL-соединением для предварительного скачивания картинок во временную папку сервера.

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

← На главную