Разработка и Конфигурация · 14 мин
Как программно прикрепить файл к документу в 1С
Как программно прикрепить файл к документу в 1С 8.3: работа с хранилищем файлов, справочником присоединенных файлов, примеры кода на встроенном языке и типичные ошибки.
Прикрепление файлов к документам — одна из самых частых задач при доработке конфигураций 1С: сканы договоров, акты, фото товара, подписанные УПД. В типовых конфигурациях на Библиотеке стандартных подсистем (БСП) для этого уже есть готовый механизм присоединенных файлов, и программно добавить файл можно несколькими строками кода. В самописных конфигурациях без БСП придётся реализовать хранение самостоятельно — через реквизит типа «ХранилищеЗначения» или собственный справочник файлов.
Выбор способа зависит от конфигурации: если в ней есть подсистема «Работа с файлами», используйте её API — это самый надёжный путь. Если БСП нет, файл обычно сохраняют в хранилище значения реквизита объекта или в отдельный справочник с привязкой к владельцу. Ниже разобраны оба сценария с рабочими примерами кода для платформы 1С:Предприятие 8.3.
Как устроено хранение файлов в 1С
В типовых конфигурациях (УТ 11, ERP, Бухгалтерия 3.0, Документооборот) присоединенные файлы хранятся в справочниках вида «<ИмяОбъекта>ПрисоединенныеФайлы» — например, «СчетНаОплатуПокупателюПрисоединенныеФайлы» или «РеализацияТоваровУслугПрисоединенныеФайлы». Каждый элемент такого справочника ссылается на владельца (документ) и содержит либо сам файл в хранилище значения, либо путь к нему в томе, если включено хранение в томах на диске.
Бинарные данные файла в 1С представлены типом «ДвоичныеДанные». Чтобы работать с файлом, его считывают с диска (на клиенте или на сервере), помещают во временное хранилище или передают напрямую, а затем записывают в базу. Важно понимать: сам по себе документ файлов не содержит — связь всегда идёт через отдельный объект (элемент справочника) с реквизитом «ВладелецФайла».
Способ 1: прикрепление через API БСП
Если конфигурация построена на БСП, используйте функцию РаботаСФайлами.ДобавитьФайл() (в новых версиях БСП — РаботаСФайлами.ДобавитьФайлСДиска() или вариант с параметрами-структурой). Она сама определит нужный справочник присоединенных файлов по типу владельца, запишет данные и заполнит служебные реквизиты: автора, дату, расширение, размер.
Типичный вызов на сервере выглядит так: сначала файл помещается во временное хранилище, затем вызывается добавление. Вот пример серверной процедуры, которая принимает адрес временного хранилища и ссылку на документ:
&НаСервере
Функция ПрикрепитьФайлКДокументу(ДокументСсылка, АдресХранилища, ИмяФайла)
ПараметрыФайла = Новый Структура;
ПараметрыФайла.Вставить("ВладелецФайлов", ДокументСсылка);
ПараметрыФайла.Вставить("Автор", Пользователи.ТекущийПользователь());
ПараметрыФайла.Вставить("ИмяБезРасширения",
СтрЗаменить(ИмяФайла, "." + РасширениеФайла(ИмяФайла), ""));
ПараметрыФайла.Вставить("РасширениеБезТочки", РасширениеФайла(ИмяФайла));
ПрисоединенныйФайл = РаботаСФайлами.ДобавитьФайл(
ПараметрыФайла, АдресХранилища);
Возврат ПрисоединенныйФайл;
КонецФункции
&НаСервереБезКонтекста
Функция РасширениеФайла(ИмяФайла)
ПозицияТочки = СтрНайти(ИмяФайла, ".", НаправлениеПоиска.СКонца);
Если ПозицияТочки = 0 Тогда
Возврат "";
КонецЕсли;
Возврат Сред(ИмяФайла, ПозицияТочки + 1);
КонецФункции
Точная сигнатура процедуры отличается между версиями БСП: в старых релизах параметры передавались позиционно (владелец, адрес, путь, имя), в новых — через структуру. Перед написанием кода откройте общий модуль РаботаСФайлами в вашей конфигурации и посмотрите актуальное описание экспортной процедуры ДобавитьФайл — это займёт минуту и избавит от ошибок несоответствия параметров.
Помещение файла во временное хранилище с клиента
На тонком или веб-клиенте нельзя напрямую читать файлы с диска на сервере — сначала файл передаётся с клиента во временное хранилище. Для этого используется асинхронный метод НачатьПомещениеФайлаВХранилище или диалог помещения файлов:
&НаКлиенте
Процедура ПрикрепитьФайл(Команда)
ОписаниеОповещения = Новый ОписаниеОповещения(
"ПослеПомещенияФайла", ЭтотОбъект);
НачатьПомещениеФайлаВХранилище(
ОписаниеОповещения,
, // адрес (заполнится автоматически)
, // имя файла — откроется диалог выбора
Истина, // интерактивно: показать диалог
УникальныйИдентификатор); // форма — владелец хранилища
КонецПроцедуры
&НаКлиенте
Процедура ПослеПомещенияФайла(Результат, Адрес, ВыбранноеИмяФайла,
ДополнительныеПараметры) Экспорт
Если Не Результат Тогда
Возврат; // пользователь отменил выбор
КонецЕсли;
НовыйФайл = ПрикрепитьФайлКДокументу(
Объект.Ссылка, Адрес, ВыбранноеИмяФайла);
Если ЗначениеЗаполнено(НовыйФайл) Тогда
ПоказатьОповещениеПользователя("Файл прикреплен",
ПолучитьНавигационнуюСсылку(НовыйФайл), ВыбранноеИмяФайла);
КонецЕсли;
КонецПроцедуры
Обратите внимание на третий параметр УникальныйИдентификатор формы: он привязывает временное хранилище к форме, и адрес остаётся валидным, пока форма открыта. Без привязки хранилище может быть очищено до вызова серверной процедуры, и вы получите ошибку «Файл не обнаружен во временном хранилище».
- 1Откройте диалог выбора файла и поместите файл во временное хранилище с привязкой к УИД формы
- 2Передайте адрес хранилища и ссылку на документ в серверную процедуру
- 3На сервере вызовите РаботаСФайлами.ДобавитьФайл с параметрами владельца
- 4Проверьте, что функция вернула заполненную ссылку на присоединенный файл
- 5Откройте документ и убедитесь, что файл виден на вкладке «Присоединенные файлы»
Способ 2: хранение файла в реквизите документа (без БСП)
В самописной конфигурации без подсистемы файлов проще всего добавить в документ реквизит типа «ХранилищеЗначения», например «ДанныеФайла», и строковые реквизиты «ИмяФайла» и «Расширение». Минус подхода — один документ хранит один файл, и при больших объёмах база растёт быстро.
&НаСервере
Процедура ЗаписатьФайлВДокумент(ДокументСсылка, АдресХранилища, ИмяФайла)
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
ДокументОбъект.ИмяФайла = ИмяФайла;
ДокументОбъект.ДанныеФайла =
Новый ХранилищеЗначения(ПолучитьИзВременногоХранилища(АдресХранилища),
Новый СжатиеДанных(9));
ДокументОбъект.Записать();
КонецПроцедуры
Сжатие данных при помещении в хранилище значения уменьшает размер для текстовых и офисных файлов, но почти бесполезно для уже сжатых форматов (JPEG, ZIP, видео). Чтобы извлечь файл обратно, используйте ДокументСсылка.ДанныеФайла.Получить() — полученные двоичные данные можно записать на диск методом Записать(ИмяФайла) или поместить во временное хранилище для скачивания на клиенте.
Способ 3: собственный справочник присоединенных файлов
Когда к одному документу нужно прикреплять несколько файлов, а БСП в конфигурации нет, создайте справочник «ПрисоединенныеФайлы» с реквизитами: «Владелец» (составной тип — ссылки на нужные документы), «ИмяФайла», «Расширение», «Размер», «ДанныеФайла» (ХранилищеЗначения). Запись элемента выполняется напрямую:
&НаСервере
Функция ДобавитьПрисоединенныйФайл(Владелец, АдресХранилища, ИмяФайла)
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресХранилища);
НовыйФайл = Справочники.ПрисоединенныеФайлы.СоздатьЭлемент();
НовыйФайл.Владелец = Владелец;
НовыйФайл.Наименование = ИмяФайла;
НовыйФайл.Размер = ДвоичныеДанные.Размер();
НовыйФайл.ДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанные,
Новый СжатиеДанных(9));
НовыйФайл.Записать();
Возврат НовыйФайл.Ссылка;
КонецФункции
Для отображения списка файлов на форме документа добавьте динамический список с отбором по владельцу — пользователь увидит все прикрепленные файлы и сможет открыть или удалить их. Не забудьте настроить права: роль должна разрешать чтение и добавление элементов справочника, иначе пользователи без полных прав получат ошибку доступа при прикреплении.
Сравнение способов хранения
Подходит для типовых конфигураций; поддерживает тома, версии, подписи. Ограничение — требует подсистему «Работа с файлами».
Простейший вариант для одного файла на документ в самописной конфигурации. Не масштабируется на несколько файлов.
Гибкое решение без БСП: много файлов на документ, свои реквизиты. Требует самостоятельной реализации прав, интерфейса и очистки.
Прикрепление файла с сервера и из внешних источников
Если файл уже лежит на сервере 1С (например, пришёл по обмену или сформирован обработкой), клиентская часть не нужна — двоичные данные читаются напрямую:
&НаСервере
Функция ПрикрепитьФайлССервера(ДокументСсылка, ПутьНаСервере)
ДвоичныеДанные = Новый ДвоичныеДанные(ПутьНаСервере);
Адрес = ПоместитьВоВременноеХранилище(ДвоичныеДанные);
ФайлИнфо = Новый Файл(ПутьНаСервере);
ПараметрыФайла = Новый Структура;
ПараметрыФайла.Вставить("ВладелецФайлов", ДокументСсылка);
ПараметрыФайла.Вставить("ИмяБезРасширения", ФайлИнфо.ИмяБезРасширения);
ПараметрыФайла.Вставить("РасширениеБезТочки",
СтрЗаменить(ФайлИнфо.Расширение, ".", ""));
Возврат РаботаСФайлами.ДобавитьФайл(ПараметрыФайла, Адрес);
КонецФункции
Учтите: серверный код выполняется под учётной записью агента сервера 1С (или службы IIS для веб-сервера), поэтому путь должен быть доступен именно этой учётной записи. Сетевые пути вида \\server\share часто недоступны из-под служебной учётки — используйте локальные каталоги сервера или заранее настройте права.
Проверка результата и типичные ошибки
После выполнения кода проверьте три вещи: функция вернула заполненную ссылку на присоединенный файл, файл виден в интерфейсе документа (вкладка «Присоединенные файлы» или команда «Присоединенные файлы» в Ещё), файл открывается и его содержимое не повреждено. Если ссылка пустая — смотрите журнал регистрации: чаще всего это ошибка прав доступа или неверный тип владельца.
Отдельная ситуация — прикрепление к новому, ещё не записанному документу. Присоединенный файл требует заполненного владельца, а у незаписанного объекта ссылки нет. Решение: сначала записать документ (хотя бы в режиме Записать() без проведения), затем прикрепить файл. В форме это обычно делают в обработчике ПослеЗаписи.
Как проверить результат
Заполненная ссылка на элемент справочника присоединенных файлов
Неопределено или пустая ссылка — ошибка записи, смотрите журнал регистрации
Файл виден в списке присоединенных файлов документа
Файл записан, но не виден — проверьте отбор динамического списка по владельцу
Файл открывается, содержимое читается корректно
Ошибка открытия или нулевой размер — данные повреждены при передаче
Ограничения и рекомендации по производительности
Платформа не накладывает жёсткого ограничения на размер прикрепляемого файла, но практические пределы определяются настройками веб-сервера (для веб-клиента и публикаций), объёмом памяти сервера и скоростью канала. Файлы в десятки мегабайт на тонком клиенте передаются заметно дольше, а на веб-клиенте могут упираться в лимиты IIS. Для больших вложений рассмотрите хранение в томах: в настройках подсистемы файлов укажите тома на диске, и в базе останутся только ссылки.
При массовом прикреплении (например, загрузке тысяч сканов обработкой) выполняйте операции пакетами с транзакциями, логируйте ошибки по каждому файлу и не держите всё в одной транзакции — иначе при сбое на последнем файле откатится вся работа. Также учитывайте, что при обмене РИБ или через EnterpriseData присоединенные файлы передаются только если это предусмотрено планом обмена.
Что важно запомнить
В типовых конфигурациях используйте РаботаСФайлами.ДобавитьФайл, предварительно поместив файл во временное хранилище с привязкой к форме. Без БСП — реквизит «ХранилищеЗначения» или собственный справочник файлов. Прикреплять можно только к записанному документу, а для больших объёмов настраивайте тома хранения вне базы.
Частые вопросы
Можно ли прикрепить файл к ещё не записанному документу?
Нет: присоединенный файл требует ссылку на владельца, а у нового объекта её нет. Сначала запишите документ, затем добавляйте файл. В форме удобно делать это в обработчике «ПослеЗаписи» или при повторном открытии документа.
Как получить список всех файлов, прикрепленных к документу?
В конфигурациях на БСП используйте функцию РаботаСФайлами.ПрикрепленныеФайлыКОбъекту(ДокументСсылка) или запрос к справочнику присоединенных файлов с отбором по реквизиту «ВладелецФайла». В самописном решении — обычный запрос к своему справочнику с условием «Владелец = &Документ».
Как программно скачать прикрепленный файл на клиент?
Получите двоичные данные через РаботаСФайлами.ДвоичныеДанныеФайла(СсылкаНаФайл), поместите их во временное хранилище и вызовите на клиенте ПолучитьФайл(Адрес, ИмяФайла, Истина) — пользователю будет предложено сохранить файл.
Почему возникает ошибка «Файл не обнаружен во временном хранилище»?
Адрес временного хранилища стал недействителен: чаще всего файл помещён без привязки к уникальному идентификатору формы, и хранилище очищено между клиентским и серверным вызовами. Передавайте УникальныйИдентификатор формы третьим параметром при помещении файла.
Можно ли прикреплять файлы в файловой базе без сервера?
Да, механизм работает и в файловом варианте: код на встроенном языке выполняется так же, временное хранилище и хранилище значений доступны. Ограничения касаются в основном производительности при больших файлах и одновременной работе нескольких пользователей.
Как ограничить типы прикрепляемых файлов, например только PDF?
В диалоге выбора задайте фильтр по маске, например «Документы PDF (.pdf)|.pdf». Дополнительно проверяйте расширение на сервере перед записью и отклоняйте неподходящие форматы — клиентский фильтр пользователь может обойти.