К статье
Практический материал

Разработка и Конфигурация · 14 мин

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

Как программно прикрепить файл к документу в 1С 8.3: работа с хранилищем файлов, справочником присоединенных файлов, примеры кода на встроенном языке и типичные ошибки.

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

Выбор способа зависит от конфигурации: если в ней есть подсистема «Работа с файлами», используйте её API — это самый надёжный путь. Если БСП нет, файл обычно сохраняют в хранилище значения реквизита объекта или в отдельный справочник с привязкой к владельцу. Ниже разобраны оба сценария с рабочими примерами кода для платформы 1С:Предприятие 8.3.

Как устроено хранение файлов в 1С

В типовых конфигурациях (УТ 11, ERP, Бухгалтерия 3.0, Документооборот) присоединенные файлы хранятся в справочниках вида «<ИмяОбъекта>ПрисоединенныеФайлы» — например, «СчетНаОплатуПокупателюПрисоединенныеФайлы» или «РеализацияТоваровУслугПрисоединенныеФайлы». Каждый элемент такого справочника ссылается на владельца (документ) и содержит либо сам файл в хранилище значения, либо путь к нему в томе, если включено хранение в томах на диске.

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

Способ 1: прикрепление через API БСП

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

Типичный вызов на сервере выглядит так: сначала файл помещается во временное хранилище, затем вызывается добавление. Вот пример серверной процедуры, которая принимает адрес временного хранилища и ссылку на документ:

&НаСервере

Функция ПрикрепитьФайлКДокументу(ДокументСсылка, АдресХранилища, ИмяФайла)

ПараметрыФайла = Новый Структура;

ПараметрыФайла.Вставить("ВладелецФайлов", ДокументСсылка);

ПараметрыФайла.Вставить("Автор", Пользователи.ТекущийПользователь());

ПараметрыФайла.Вставить("ИмяБезРасширения",

СтрЗаменить(ИмяФайла, "." + РасширениеФайла(ИмяФайла), ""));

ПараметрыФайла.Вставить("РасширениеБезТочки", РасширениеФайла(ИмяФайла));

ПрисоединенныйФайл = РаботаСФайлами.ДобавитьФайл(

ПараметрыФайла, АдресХранилища);

Возврат ПрисоединенныйФайл;

КонецФункции

&НаСервереБезКонтекста

Функция РасширениеФайла(ИмяФайла)

ПозицияТочки = СтрНайти(ИмяФайла, ".", НаправлениеПоиска.СКонца);

Если ПозицияТочки = 0 Тогда

Возврат "";

КонецЕсли;

Возврат Сред(ИмяФайла, ПозицияТочки + 1);

КонецФункции

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

Помещение файла во временное хранилище с клиента

На тонком или веб-клиенте нельзя напрямую читать файлы с диска на сервере — сначала файл передаётся с клиента во временное хранилище. Для этого используется асинхронный метод НачатьПомещениеФайлаВХранилище или диалог помещения файлов:

&НаКлиенте

Процедура ПрикрепитьФайл(Команда)

ОписаниеОповещения = Новый ОписаниеОповещения(

"ПослеПомещенияФайла", ЭтотОбъект);

НачатьПомещениеФайлаВХранилище(

ОписаниеОповещения,

, // адрес (заполнится автоматически)

, // имя файла — откроется диалог выбора

Истина, // интерактивно: показать диалог

УникальныйИдентификатор); // форма — владелец хранилища

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

&НаКлиенте

Процедура ПослеПомещенияФайла(Результат, Адрес, ВыбранноеИмяФайла,

ДополнительныеПараметры) Экспорт

Если Не Результат Тогда

Возврат; // пользователь отменил выбор

КонецЕсли;

НовыйФайл = ПрикрепитьФайлКДокументу(

Объект.Ссылка, Адрес, ВыбранноеИмяФайла);

Если ЗначениеЗаполнено(НовыйФайл) Тогда

ПоказатьОповещениеПользователя("Файл прикреплен",

ПолучитьНавигационнуюСсылку(НовыйФайл), ВыбранноеИмяФайла);

КонецЕсли;

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

Обратите внимание на третий параметр УникальныйИдентификатор формы: он привязывает временное хранилище к форме, и адрес остаётся валидным, пока форма открыта. Без привязки хранилище может быть очищено до вызова серверной процедуры, и вы получите ошибку «Файл не обнаружен во временном хранилище».

Порядок действий при прикреплении файла
  1. 1
    Откройте диалог выбора файла и поместите файл во временное хранилище с привязкой к УИД формы
  2. 2
    Передайте адрес хранилища и ссылку на документ в серверную процедуру
  3. 3
    На сервере вызовите РаботаСФайлами.ДобавитьФайл с параметрами владельца
  4. 4
    Проверьте, что функция вернула заполненную ссылку на присоединенный файл
  5. 5
    Откройте документ и убедитесь, что файл виден на вкладке «Присоединенные файлы»

Способ 2: хранение файла в реквизите документа (без БСП)

В самописной конфигурации без подсистемы файлов проще всего добавить в документ реквизит типа «ХранилищеЗначения», например «ДанныеФайла», и строковые реквизиты «ИмяФайла» и «Расширение». Минус подхода — один документ хранит один файл, и при больших объёмах база растёт быстро.

&НаСервере

Процедура ЗаписатьФайлВДокумент(ДокументСсылка, АдресХранилища, ИмяФайла)

ДокументОбъект = ДокументСсылка.ПолучитьОбъект();

ДокументОбъект.ИмяФайла = ИмяФайла;

ДокументОбъект.ДанныеФайла =

Новый ХранилищеЗначения(ПолучитьИзВременногоХранилища(АдресХранилища),

Новый СжатиеДанных(9));

ДокументОбъект.Записать();

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

Сжатие данных при помещении в хранилище значения уменьшает размер для текстовых и офисных файлов, но почти бесполезно для уже сжатых форматов (JPEG, ZIP, видео). Чтобы извлечь файл обратно, используйте ДокументСсылка.ДанныеФайла.Получить() — полученные двоичные данные можно записать на диск методом Записать(ИмяФайла) или поместить во временное хранилище для скачивания на клиенте.

Способ 3: собственный справочник присоединенных файлов

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

&НаСервере

Функция ДобавитьПрисоединенныйФайл(Владелец, АдресХранилища, ИмяФайла)

ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресХранилища);

НовыйФайл = Справочники.ПрисоединенныеФайлы.СоздатьЭлемент();

НовыйФайл.Владелец = Владелец;

НовыйФайл.Наименование = ИмяФайла;

НовыйФайл.Размер = ДвоичныеДанные.Размер();

НовыйФайл.ДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанные,

Новый СжатиеДанных(9));

НовыйФайл.Записать();

Возврат НовыйФайл.Ссылка;

КонецФункции

Для отображения списка файлов на форме документа добавьте динамический список с отбором по владельцу — пользователь увидит все прикрепленные файлы и сможет открыть или удалить их. Не забудьте настроить права: роль должна разрешать чтение и добавление элементов справочника, иначе пользователи без полных прав получат ошибку доступа при прикреплении.

Сравнение способов хранения

API БСП (РаботаСФайлами)

Подходит для типовых конфигураций; поддерживает тома, версии, подписи. Ограничение — требует подсистему «Работа с файлами».

Реквизит документа

Простейший вариант для одного файла на документ в самописной конфигурации. Не масштабируется на несколько файлов.

Свой справочник файлов

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

Прикрепление файла с сервера и из внешних источников

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

&НаСервере

Функция ПрикрепитьФайлССервера(ДокументСсылка, ПутьНаСервере)

ДвоичныеДанные = Новый ДвоичныеДанные(ПутьНаСервере);

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

ФайлИнфо = Новый Файл(ПутьНаСервере);

ПараметрыФайла = Новый Структура;

ПараметрыФайла.Вставить("ВладелецФайлов", ДокументСсылка);

ПараметрыФайла.Вставить("ИмяБезРасширения", ФайлИнфо.ИмяБезРасширения);

ПараметрыФайла.Вставить("РасширениеБезТочки",

СтрЗаменить(ФайлИнфо.Расширение, ".", ""));

Возврат РаботаСФайлами.ДобавитьФайл(ПараметрыФайла, Адрес);

КонецФункции

Учтите: серверный код выполняется под учётной записью агента сервера 1С (или службы IIS для веб-сервера), поэтому путь должен быть доступен именно этой учётной записи. Сетевые пути вида \\server\share часто недоступны из-под служебной учётки — используйте локальные каталоги сервера или заранее настройте права.

Проверка результата и типичные ошибки

После выполнения кода проверьте три вещи: функция вернула заполненную ссылку на присоединенный файл, файл виден в интерфейсе документа (вкладка «Присоединенные файлы» или команда «Присоединенные файлы» в Ещё), файл открывается и его содержимое не повреждено. Если ссылка пустая — смотрите журнал регистрации: чаще всего это ошибка прав доступа или неверный тип владельца.

Типичные ошибки
01
Вызов ДобавитьФайл с пустым адресом хранилища — файл не помещён на клиенте или хранилище очищено; передавайте УИД формы при помещении
02
Передача ссылки на форму документа вместо ссылки на документ — для нового незаписанного документа сначала выполните Записать(), затем прикрепляйте файл
03
Несовпадение сигнатуры РаботаСФайлами.ДобавитьФайл с версией БСП — откройте модуль и сверьте параметры
04
Чтение файла с диска на сервере, когда файл лежит на компьютере пользователя — на сервере этот путь недоступен, нужен перенос через временное хранилище
05
Отсутствие прав на справочник присоединенных файлов у роли пользователя — добавьте права на чтение и добавление

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

Контрольные точки

Как проверить результат

Возвращаемое значение функции добавления
Норма

Заполненная ссылка на элемент справочника присоединенных файлов

Тревожный признак

Неопределено или пустая ссылка — ошибка записи, смотрите журнал регистрации

Отображение в документе
Норма

Файл виден в списке присоединенных файлов документа

Тревожный признак

Файл записан, но не виден — проверьте отбор динамического списка по владельцу

Открытие файла
Норма

Файл открывается, содержимое читается корректно

Тревожный признак

Ошибка открытия или нулевой размер — данные повреждены при передаче

Ограничения и рекомендации по производительности

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

При массовом прикреплении (например, загрузке тысяч сканов обработкой) выполняйте операции пакетами с транзакциями, логируйте ошибки по каждому файлу и не держите всё в одной транзакции — иначе при сбое на последнем файле откатится вся работа. Также учитывайте, что при обмене РИБ или через EnterpriseData присоединенные файлы передаются только если это предусмотрено планом обмена.

Итог

Что важно запомнить

В типовых конфигурациях используйте РаботаСФайлами.ДобавитьФайл, предварительно поместив файл во временное хранилище с привязкой к форме. Без БСП — реквизит «ХранилищеЗначения» или собственный справочник файлов. Прикреплять можно только к записанному документу, а для больших объёмов настраивайте тома хранения вне базы.

Частые вопросы

Можно ли прикрепить файл к ещё не записанному документу?

Нет: присоединенный файл требует ссылку на владельца, а у нового объекта её нет. Сначала запишите документ, затем добавляйте файл. В форме удобно делать это в обработчике «ПослеЗаписи» или при повторном открытии документа.

Как получить список всех файлов, прикрепленных к документу?

В конфигурациях на БСП используйте функцию РаботаСФайлами.ПрикрепленныеФайлыКОбъекту(ДокументСсылка) или запрос к справочнику присоединенных файлов с отбором по реквизиту «ВладелецФайла». В самописном решении — обычный запрос к своему справочнику с условием «Владелец = &Документ».

Как программно скачать прикрепленный файл на клиент?

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

Почему возникает ошибка «Файл не обнаружен во временном хранилище»?

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

Можно ли прикреплять файлы в файловой базе без сервера?

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

Как ограничить типы прикрепляемых файлов, например только PDF?

В диалоге выбора задайте фильтр по маске, например «Документы PDF (.pdf)|.pdf». Дополнительно проверяйте расширение на сервере перед записью и отклоняйте неподходящие форматы — клиентский фильтр пользователь может обойти.