При импорте данных, интеграции с интернет-магазинами или загрузке прайс-листов перед разработчиком часто возникает задача привязать изображения или сертификаты к карточкам номенклатуры. В современных конфигурациях «1С:Предприятие 8» на базе БСП (таких как «Управление торговлей 11», «ERP Управление предприятием» или «Комплексная автоматизация») файлы хранятся в подчиненных справочниках вида ИмяОбъектаПрисоединенныеФайлы.
Попытка создать такой элемент «в лоб» через стандартный метод СоздатьЭлемент() часто приводит к ошибкам работы с файловой системой. Разберем типичные ошибки ручного создания элементов справочника присоединенных файлов, выясним причины сбоев и детально рассмотрим два пути решения: исправление ручной записи и правильный архитектурный метод через программный интерфейс БСП.
Типичная ситуация: разработчик пишет код, который создает элемент справочника НоменклатураПрисоединенныеФайлы, заполняет реквизиты пути, тома и имени файла, после чего записывает его. Элемент успешно появляется в базе данных, но при попытке открыть файл в интерфейсе системы возникает ошибка:
«Не удалось открыть файл... по причине: двоичные данные файла были удалены. Возможно, файл очищен как ненужный или удален антивирусной программой.»
Выясним причину этой проблемы. Дело в том, что в современных конфигурациях файлы привязываются к объектам не просто строковыми путями. Система БСП использует сложные механизмы кэширования, хранения в томах на диске или в СУБД, а также контролирует уникальность имен файлов. При простом заполнении реквизитов элемента справочника физическая запись файла на диск в структуру томов не происходит, либо происходит некорректно, из-за чего система считает данные поврежденными.
Если по каким-то причинам нам требуется обойти стандартные механизмы БСП и записать файлы напрямую, необходимо строго соблюдать соответствие типов реквизитов справочника и корректно рассчитывать относительный путь к файлу на диске.
Проанализируем готовый рабочий код ручного добавления файла, к которому пришел автор темы после исправления всех ошибок:
Функция СоздатьПрикрФайлНаСервере(Знач Результат, Знач Выборка)
// Вычисляем относительный путь файла без учета пути самого Тома
ПутьКФайлу = СтрЗаменить(Результат.ПолноеИмяФайла, Результат.Том.ПолныйПутьWindows, "");
// Приводим ссылку номенклатуры к определяемому типу владельца файлов
ТипСтр = Новый ОписаниеТипов(Метаданные.ОпределяемыеТипы.ВладелецПрисоединенныхФайлов.Тип);
ВладелецФайлов = ТипСтр.ПривестиЗначение(Выборка.Ссылка);
СуществующийФайл = Новый Файл(Результат.ПолноеИмяФайла);
Спр = Справочники.НоменклатураПрисоединенныеФайлы.СоздатьЭлемент();
Спр.Наименование = Результат.ИмяФайла;
Спр.ВладелецФайла = ВладелецФайлов;
Спр.Автор = ПараметрыСеанса.ТекущийПользователь;
Спр.ИндексКартинки = РаботаСФайламиСлужебныйКлиентСервер.ПолучитьИндексПиктограммыФайла(Неопределено);
Спр.СтатусИзвлеченияТекста = Перечисления.СтатусыИзвлеченияТекстаФайлов.Извлечен;
Спр.ТипХраненияФайла = Перечисления.ТипыХраненияФайлов.ВТомахНаДиске;
Спр.ПутьКФайлу = ПутьКФайлу; // Здесь должен быть путь файла относительно Тома
Спр.Том = Результат.Том.Том; // Передаем СправочникСсылка.ТомаХраненияФайлов
Спр.Описание = "Картинка " + ПутьКФайлу;
Спр.Расширение = "jpg";
Спр.Заполнить(Неопределено);
Спр.ДатаМодификацииУниверсальная = СуществующийФайл.ПолучитьУниверсальноеВремяИзменения();
Спр.Размер = СуществующийФайл.Размер();
Спр.ДатаСоздания = СуществующийФайл.ПолучитьВремяИзменения();
Спр.Изменил = ПараметрыСеанса.ТекущийПользователь;
Попытка
Спр.Записать();
Сообщить("Записан " + Результат.ИмяФайла + " --> " + ВладелецФайлов);
Возврат Спр.Ссылка;
Исключение
Сообщить("При записи " + Результат.ИмяФайла + " возникла ошибка: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
Рассмотрим подробнее ключевые моменты, которые были исправлены в данном коде по сравнению с первоначальной неудачной попыткой:
ВладелецФайла имеет определяемый тип ОпределяемыеТипы.ВладелецПрисоединенныхФайлов. Прямое присвоение ссылки номенклатуры может вызвать конфликт типов в некоторых версиях платформы, поэтому перед записью мы явно приводим тип с помощью объекта ОписаниеТипов.ПутьКФайлу не должен содержать полный путь операционной системы (например, D:\Shares\1C_Files\Tom1\Catalog\image.jpg). В нем должен храниться только относительный путь внутри тома (например, Catalog\image.jpg). Путь к самому тому определяется через реквизит Том.Том необходимо передавать ссылку на элемент справочника томов хранения файлов, а не строковое представление или объект описания тома.Файл.Несмотря на то, что приведенный выше ручной код работает, использовать его в реальных задачах крайне не рекомендуется по следующим причинам:
НаличиеФайлов). В этом регистре хранится информация о том, прикреплен ли к объекту файл (благодаря чему в списках горит иконка «скрепки»). Ручная запись в справочник этот регистр не обновляет, и пользователи не увидят значок прикрепленного файла в форме списка.Для корректного решения нашей задачи воспользуемся программным интерфейсом подсистемы «Работа с файлами» БСП. Стандартный метод РаботаСФайлами.ДобавитьФайл берет на себя всю рутину по созданию элементов, записи данных в СУБД или на диск, а также обновлению служебных регистров сведений.
Рассмотрим по шагам правильный алгоритм добавления файла к номенклатуре:
// 1. Помещаем двоичные данные файла во временное хранилище
ДвоичныеДанные = Новый ДвоичныеДанные(ПолныйПутьКФайлуНаДиске);
АдресВХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанные);
// 2. Инициализируем стандартную структуру параметров добавления файла БСП
ПараметрыФайла = РаботаСФайлами.ПараметрыДобавленияФайла();
ПараметрыФайла.Автор = Пользователи.ТекущийПользователь();
ПараметрыФайла.ВладелецФайлов = НоменклатураСсылка; // Передаем ссылку напрямую, приведение типов не требуется
ПараметрыФайла.ИмяБезРасширения = "Имя_Файла_Номенклатуры";
ПараметрыФайла.РасширениеБезТочки = "jpg";
// 3. Генерируем пустую ссылку нужного подчиненного справочника файлов.
// Это необходимо, чтобы БСП поняла, в какой именно справочник добавлять файл.
НоваяСсылкаНаФайл = Справочники.НоменклатураПрисоединенныеФайлы.ПолучитьСсылку();
// 4. Вызываем стандартный метод БСП для добавления файла
СсылкаНаСозданныйФайл = РаботаСФайлами.ДобавитьФайл(
ПараметрыФайла,
АдресВХранилище,
"Основное изображение номенклатуры", // Описание файла
, // Хранить версию (необязательно, по умолчанию Истина)
НоваяСсылкаНаФайл
);
Проанализируем преимущества данного подхода:
РаботаСФайлами.ДобавитьФайл самостоятельно анализирует настройки системы (где именно хранятся файлы — в базе или в томах на диске). Разработчику больше не нужно вручную вырезать пути, проверять доступность папок или определять структуру хранения.При программной работе с присоединенными файлами в «1С:Предприятии 8» всегда следует отдавать предпочтение штатным механизмам БСП. Ручное создание элементов справочников через СоздатьElement() допускается только в редких случаях одноразового переноса данных в закрытых системах, и требует досконального заполнения всех связанных реквизитов и регистров. Для надежной промышленной эксплуатации используйте функции общего модуля РаботаСФайлами.