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

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

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

Разберем архитектуру хранения файлов в современных конфигурациях

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

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

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

Способ 1. Ручное копирование через регистр сведений

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

Предположим, у нас есть СсылкаНаСтарыйФайл и мы создали НовыйФайлОбъект. Рассмотрим пример кода для переноса данных:


// 1. Создаем элемент в справочнике-приемнике
НовыйФайлОбъект = Справочники.ЗаявкаНаРасходованиеСредствПрисоединенныеФайлы.СоздатьЭлемент();
ЗаполнитьЗначенияСвойств(НовыйФайлОбъект, СсылкаНаСтарыйФайл);
НовыйФайлОбъект.ВладелецФайла = ДокументПриемник;
НовыйФайлОбъект.УстановитьНовыйСсылку(); // Важно получить ссылку до записи для регистра
НоваяСсылка = НовыйФайлОбъект.ПолучитьСсылкуНового();
НовыйФайлОбъект.Записать();

// 2. Копируем двоичные данные из регистра
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ДвоичныеДанныеФайлов.ХранилищеФайла
    |ИЗ
    |	РегистрСведений.ДвоичныеДанныеФайлов КАК ДвоичныеДанныеФайлов
    |ГДЕ
    |	ДвоичныеДанныеФайлов.Файл = &СтарыйФайл";
Запрос.УстановитьПараметр("СтарыйФайл", СсылкаНаСтарыйФайл);
Результат = Запрос.Выполнить();

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

Важный нюанс: Этот способ сработает только в том случае, если файлы хранятся в базе. Если файлы хранятся в томах на диске, этот код не поможет, так как в регистре будет пусто, а физический файл на диске не будет продублирован под новым именем (UUID).

Способ 2. Использование программного интерфейса БСП (Рекомендуемый)

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

Рассмотрим по шагам, как это реализовать:

  1. Сначала получаем двоичные данные исходного файла.
  2. Затем добавляем новый файл в объект-приемник, передавая эти данные.

// Получаем двоичные данные исходного файла
ДанныеФайла = РаботаСФайлами.ДвоичныеДанныеФайла(СсылкаНаСтарыйФайл);

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

// Добавляем файл к новому документу
НовыйФайлСсылка = РаботаСФайлами.ДобавитьФайл(
    ДокументПриемник, 
    ДанныеФайла, 
    СсылкаНаСтарыйФайл.Наименование, 
    "Копия при создании на основании", 
    ПараметрыФайла
);

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

Почему старый код перестал работать после обновления?

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

Подведем итоги

При копировании файлов между документами помните о следующих правилах:

Соблюдение этих рекомендаций позволит вам избежать ошибок при работе с файлами и обеспечит сохранность данных ваших пользователей.

← На главную