Как программно скопировать присоединенный файл между разными объектами в 1С?

Программист IT и автоматизация бизнеса
← На главную

При разработке в системе 1С:Предприятие 8 часто возникает задача переноса или дублирования присоединенных файлов из одного документа в другой. Например, когда необходимо прикрепить сертификат соответствия из ПоступленияТоваровУслуг к документу РеализацияТоваровУслуг. Обычное копирование элемента справочника присоединенных файлов не дает результата, так как физически данные хранятся отдельно от карточки описания файла. В данной статье мы подробно разберем, как правильно реализовать этот механизм, используя возможности Библиотеки стандартных подсистем (БСП).

Почему простое копирование справочника не работает?

Проанализируем архитектуру хранения файлов в современных конфигурациях. В 1С присоединенный файл — это совокупность записи в справочнике (например, Справочник.РеализацияТоваровУслугПрисоединенныеФайлы) и самих двоичных данных. Сами данные могут находиться в регистре сведений (если выбрано хранение в информационной базе) или на томе хранения (если файлы хранятся на диске). Когда мы просто создаем новый элемент справочника и копируем в него реквизиты старого, ссылка на фактические данные в хранилище не создается автоматически, и система выдает ошибку о том, что файл пуст или удален.

Метод 1: Использование универсальных функций БСП

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

Разберем алгоритм действий по шагам:

  1. Получаем ссылку на файл-источник, который нужно скопировать.
  2. Извлекаем двоичные данные этого файла.
  3. Определяем объект-получатель (владельца), к которому будет прикреплена копия.
  4. Вызываем процедуру добавления, которая создаст новую запись в нужном справочнике и свяжет её с данными.

Посмотрим на пример кода, реализующий эту логику (для написания подобных скриптов удобно использовать консоль кода с ИИ-помощником — поможет ИИ-помощник для написания кода 1С):


// Определяем источник и получатель
СсылкаНаФайлИсточник = ОбъектИсточник.Ссылка; // Элемент справочника присоединенных файлов
ДокументПолучатель = СсылкаНаРеализацию;

// 1. Получаем данные файла-источника
ДанныеФайла = ПрисоединенныеФайлы.ПолучитьДанныеФайла(СсылкаНаФайлИсточник);

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

// 3. Помещаем данные во временное хранилище
АдресВоВременномХранилище = ПоместитьВоВременноеХранилище(ДанныеФайла.ДвоичныеДанные);

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

Метод 2: Копирование через временный файл на диске

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

Рассмотрим классический алгоритм «в 5 строчек»:

  1. Получаем двоичные данные из источника через ПрисоединенныеФайлы.ПолучитьДанныеФайла.
  2. Создаем временное имя файла с помощью функции ПолучитьИмяВременногоФайла().
  3. Записываем двоичные данные на диск.
  4. Вызываем метод БСП для добавления файла, указав путь к временному файлу.
  5. Удаляем временный файл после успешной записи.

Метод 3: Адаптация типовой процедуры СкопироватьПрисоединенныеФайлы

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

Для решения этой проблемы можно переписать логику, чтобы она динамически определяла справочник-владелец для каждого типа объекта. Выясним, как это реализовать:


Процедура УниверсальноеКопированиеФайлов(Источник, Получатель) Экспорт
    
    // Получаем массив файлов источника
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Файлы.Ссылка КАК Ссылка
        |ИЗ
        |   " + ПрисоединенныеФайлы.ИмяСправочникаФайлов(Источник.Метаданные()) + " КАК Файлы
        |ГДЕ
        |   Файлы.ВладелецФайла = &Источник";
    
    Запрос.УстановитьПараметр("Источник", Источник);
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    Пока Выборка.Следующая() Цикл
        // Используем метод КопироватьФайл, который учитывает разницу в типах справочников
        ПрисоединенныеФайлы.КопироватьФайл(Выборка.Ссылка, Получатель);
    КонецЦикла;

КонецПроцедуры

Важные нюансы при копировании

Работая с файлами, необходимо учитывать следующие моменты (а проверить качество написанного кода поможет статический анализатор — есть автоматический статический анализатор 1С), чтобы избежать потери данных или ошибок системы:

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

← На главную