БСП в 1С

Присоединённые файлы в БСП: получить, добавить и проверить программно

Коротко

Содержимое присоединённого файла берётся одной строкой: РаботаСФайлами.ДвоичныеДанныеФайла(ФайлСсылка). Для нескольких файлов есть пакетный вариант ДвоичныеДанныеФайлов(Массив) — он возвращает Соответствие «ссылка → двоичные данные» за один запрос.

Список файлов объекта заполняет ЗаполнитьПрисоединенныеФайлыКОбъекту(), новый файл проще всего создать через ДобавитьФайлСДиска(), а перед добавлением стоит спросить КОбъектуМожноПрисоединятьФайлы() — иначе получите исключение на определении справочника хранения.

Где в БСП живут присоединённые файлы

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

  • Владелец файлов — любой объект, тип которого входит в определяемый тип ВладелецПрисоединенныхФайлов: документ, элемент справочника, папка файлов.
  • Справочник хранения<ИмяВладельца>ПрисоединенныеФайлы либо общий справочник Файлы. Именно его элементы — присоединённые файлы.
  • Определяемый тип ПрисоединенныйФайл — объединение всех справочников хранения. По нему БСП проверяет входные параметры своих методов.
  • Двоичные данные лежат отдельно: в регистре сведений ХранилищеФайлов либо в томах на диске. Читать регистр напрямую не нужно — для этого есть публичные функции.

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

Как получить двоичные данные присоединённого файла

Базовая функция чтения — ДвоичныеДанныеФайла(). На вход ссылка на элемент справочника с файлом, на выходе ДвоичныеДанные:

// Сохранение данных присоединённого файла на сервере
ДанныеФайла = РаботаСФайлами.ДвоичныеДанныеФайла(ФайлСсылка, Ложь);

Если ДанныеФайла <> Неопределено Тогда
    ДанныеФайла.Записать("C:\Выгрузка\" + ФайлСсылка.Наименование + "." + ФайлСсылка.Расширение);
КонецЕсли;
РаботаСФайлами.ДвоичныеДанныеФайла
ПрисоединенныйФайлОпределяемыйТип.ПрисоединенныйФайл — ссылка на элемент справочника с файлом
ВызыватьИсключениеБулево, по умолчанию Истина
ДвоичныеДанные, Неопределено

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

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

Пакетное получение данных нескольких файлов

Вызывать ДвоичныеДанныеФайла() в цикле по сотне файлов — это сотня запросов к базе. Для пачки есть отдельная функция, которая собирает всё одним запросом:

ФайлыДокумента = Новый Массив;
РаботаСФайлами.ЗаполнитьПрисоединенныеФайлыКОбъекту(ДокументСсылка, ФайлыДокумента);

// Один запрос на все файлы вместо цикла с обращениями к базе
ДанныеФайлов = РаботаСФайлами.ДвоичныеДанныеФайлов(ФайлыДокумента, Ложь);

Для Каждого КлючИЗначение Из ДанныеФайлов Цикл
    ФайлСсылка     = КлючИЗначение.Ключ;
    ДвоичныеДанные = КлючИЗначение.Значение;
    ЗаписьZip.Добавить(ДвоичныеДанные, ФайлСсылка.Наименование);
КонецЦикла;
РаботаСФайлами.ДвоичныеДанныеФайлов
ПрисоединенныеФайлыМассив из ОпределяемыйТип.ПрисоединенныйФайл, все элементы одного типа
ВызыватьИсключениеБулево, по умолчанию Истина
Соответствие (ключ — ссылка на файл, значение — ДвоичныеДанные)

Три особенности, которые видны только в коде модуля:

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

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

В ИИ Консоли кода: попросите агента выгрузить присоединённые файлы конкретного документа в ZIP или в каталог на сервере. Он сам подберёт справочник хранения для вашего типа владельца, соберёт массив файлов и прогонит пакетное получение данных на вашей базе — быстрее, чем выяснять имя справочника по конфигурации вручную.

Список 1С БСП файлов, присоединённых к объекту

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

Файлы = Новый Массив;   // массив создаём сами, процедура только дополняет его
РаботаСФайлами.ЗаполнитьПрисоединенныеФайлыКОбъекту(ДокументСсылка, Файлы);

Сообщить("Присоединено файлов: " + Файлы.Количество());
РаботаСФайлами.ЗаполнитьПрисоединенныеФайлыКОбъекту
ВладелецФайлаОпределяемыйТип.ВладелецПрисоединенныхФайлов
ФайлыМассив, в который добавляются ссылки на найденные файлы

Это процедура, а не функция: она добавляет ссылки в переданный массив, не очищая его. Удобно для сбора файлов сразу по нескольким объектам в один список — достаточно вызвать её в цикле с тем же массивом.

Если владелец не заполнен или это ссылка на Справочник.ИдентификаторыОбъектовМетаданных, процедура тихо выходит, оставив массив как есть. Пустой результат поэтому означает и «файлов нет», и «передали пустую ссылку».

Как добавить присоединённый файл с диска

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

// Файл должен лежать на сервере 1С, не на клиенте
ФайлСсылка = РаботаСФайлами.ДобавитьФайлСДиска(ДокументСсылка, "/opt/exchange/act-1024.pdf");

Сообщить("Создан файл: " + Строка(ФайлСсылка));
РаботаСФайлами.ДобавитьФайлСДиска
ВладелецФайловОпределяемыйТип.ВладелецПрисоединенныхФайлов — объект, к которому крепится файл
ПутьКФайлуНаДискеСтрока — полный путь с именем и расширением, файл на сервере
ОпределяемыйТип.ПрисоединенныйФайл

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

Пустой ВладелецФайлов — исключение категории «ОшибкаКонфигурации» с явным текстом про незаполненный параметр. Извлечение текста зависит от настроек базы: при серверном извлечении его сделает регламентное задание позже, иначе на Windows-сервере текст извлекается тут же.

Устаревший аналог СоздатьФайлНаОсновеФайлаНаДиске() в новом коде не используют — он просто переадресует вызов в ДобавитьФайлСДиска().

Новая ссылка на файл и добавление данных из памяти

Когда данные не лежат на диске, а формируются в коде (печатная форма, ответ HTTP-сервиса, выгрузка), файл добавляют из временного хранилища. Ссылку на будущий элемент справочника выдаёт НоваяСсылкаНаФайл():

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

ПараметрыФайла = РаботаСФайлами.ПараметрыДобавленияФайла();
ПараметрыФайла.ВладелецФайлов              = ДокументСсылка;
ПараметрыФайла.ИмяБезРасширения            = "Акт сверки";
ПараметрыФайла.РасширениеБезТочки          = "pdf";
ПараметрыФайла.ВремяИзмененияУниверсальное = ТекущаяУниверсальнаяДата();

ФайлСсылка = РаботаСФайлами.ДобавитьФайл(ПараметрыФайла, Адрес, "", "Акт сверки за период", СсылкаНаФайл);
РаботаСФайлами.НоваяСсылкаНаФайл
ВладелецФайловОпределяемыйТип.ВладелецПрисоединенныхФайлов
ИмяСправочникаСтрока — имя справочника хранения; Неопределено — вычислить по владельцу
ОпределяемыйТип.ПрисоединенныйФайл — ссылка на ещё не записанный элемент

Смысл предварительной ссылки — знать идентификатор файла до его записи: положить его в регистр, в лог обмена или в ответ веб-сервиса. Если у владельца несколько справочников хранения, вычислить его автоматически нельзя — ИмяСправочника становится обязательным, иначе будет исключение.

// Тот же вызов, когда справочник хранения задан явно
СсылкаНаФайл = РаботаСФайлами.НоваяСсылкаНаФайл(ДокументСсылка, "ЗаказКлиентаПрисоединенныеФайлы");
РаботаСФайлами.ДобавитьФайл
ПараметрыФайластруктура из ПараметрыДобавленияФайла: ВладелецФайлов, ИмяБезРасширения, РасширениеБезТочки, Автор, ГруппаФайлов, Служебный
АдресФайлаВоВременномХранилищеСтрока — адрес двоичных данных
АдресВременногоХранилищаТекстаСтрока — извлечённый текст
ОписаниеСтрока
НоваяСсылкаНаФайлссылка из НоваяСсылкаНаФайл
ОпределяемыйТип.ПрисоединенныйФайл

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

Проверка: можно ли присоединять файлы к объекту

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

Если РаботаСФайлами.КОбъектуМожноПрисоединятьФайлы(ОбъектСсылка) Тогда
    РаботаСФайлами.ДобавитьФайлСДиска(ОбъектСсылка, ПутьКФайлу);
Иначе
    ЗаписьЖурналаРегистрации("Обмен.Файлы", УровеньЖурналаРегистрации.Предупреждение,,,
        "К объекту нельзя присоединять файлы: " + Строка(ТипЗнч(ОбъектСсылка)));
КонецЕсли;
РаботаСФайлами.КОбъектуМожноПрисоединятьФайлы
ВладелецФайловОпределяемыйТип.ВладелецПрисоединенныхФайлов
ИмяСправочникаСтрока, по умолчанию "" — проверить конкретное хранилище файлов
Булево

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

Обратите внимание: право доступа входит в проверку. Один и тот же объект даст Истина администратору и Ложь пользователю с урезанной ролью — это штатное поведение, а не ошибка конфигурации.

Обновить данные существующего присоединённого файла

Перезаписать содержимое файла присваиванием реквизита нельзя: двоичные данные лежат в отдельном регистре или в томе. Для файлов без версий есть ОбновитьФайл():

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

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

Метод работает в транзакции с управляемой блокировкой элемента справочника, поэтому вызывать его внутри своей длинной транзакции не стоит. Два адреса временного хранилища читаются из структуры напрямую — если свойств нет, будет ошибка обращения к несуществующему свойству, а не понятное сообщение. Остальные свойства проверяются через Свойство() и потому необязательны.

Дата модификации ведёт себя нестандартно: по умолчанию ставится текущая универсальная дата, а переданное значение применяется, только если оно меньше текущей. Будущей датой файл пометить не получится. Для файлов с версиями метод не предназначен — там версия добавляется средствами подсистемы версионирования.

Сведения о файле: ДанныеФайла вместо чтения реквизитов

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

ПараметрыДанныхФайла = РаботаСФайламиКлиентСервер.ПараметрыДанныхФайла();
ПараметрыДанныхФайла.ИдентификаторФормы = УникальныйИдентификатор;
ПараметрыДанныхФайла.ВызыватьИсключение = Ложь;

Сведения = РаботаСФайлами.ДанныеФайла(ФайлСсылка, ПараметрыДанныхФайла);

Если Сведения <> Неопределено Тогда
    Сообщить(Сведения.ИмяФайла + ", " + Сведения.Размер + " байт, подписан: " + Сведения.ПодписанЭП);
КонецЕсли;

В структуре среди прочего есть Ссылка, Владелец, ИмяФайла, Расширение, Размер, ДатаМодификацииУниверсальная, ПодписанЭП, Зашифрован, ПометкаУдаления, ТекущаяВерсия, НомерВерсии, Том, Автор и СсылкаНаДвоичныеДанныеФайла — адрес данных во временном хранилище.

Важный побочный эффект: при ДляРедактирования = Истина файл занимается текущим пользователем — это интерактивный сценарий. Для фоновой обработки этот флаг не включают, иначе файлы останутся заблокированными.

В ИИ Консоли кода: опишите задачу словами — «прикрепить сформированный PDF к заказу клиента» или «проверить, у каких документов за месяц нет присоединённых файлов». Агент напишет код на функциях РаботаСФайлами и выполнит его на вашей базе, показав результат: не придётся вручную сверять имена справочников хранения и состав параметров.

Частые ошибки при работе с присоединёнными файлами БСП

  • Разнотипные файлы в ДвоичныеДанныеФайлов(). Все элементы массива должны быть одного типа справочника хранения. Иначе — исключение категории «ОшибкаКонфигурации». Группируйте файлы по ТипЗнч() перед вызовом.
  • Результат пакетной функции считают полным. Файлы без прав на чтение и файлы с отсутствующими двоичными данными (при ВызыватьИсключение = Ложь) в Соответствие не попадают. Проверяйте наличие ключа, а не индекс массива.
  • Массив не создан перед ЗаполнитьПрисоединенныеФайлыКОбъекту(). Это процедура: она дополняет переданную коллекцию, но не создаёт её и не чистит. Повторный вызов с тем же массивом накапливает дубли.
  • Путь к файлу в ДобавитьФайлСДиска() — клиентский. Файл читается на сервере 1С. Локальный путь пользователя в клиент-серверной базе даст ошибку открытия файла; данные с клиента передавайте через временное хранилище и ДобавитьФайл().
  • Несколько справочников хранения у владельца. Тогда НоваяСсылкаНаФайл() и ДобавитьФайл() без явного имени справочника (или без параметра НоваяСсылкаНаФайл) выбрасывают исключение — определить хранилище автоматически невозможно.
  • Неполная структура в ОбновитьФайл(). Свойства АдресФайлаВоВременномХранилище и АдресВременногоХранилищаТекста читаются напрямую и обязательны, второе — хотя бы пустой строкой.
  • Размер файла больше допустимого. Ограничение возвращает РаботаСФайлами.МаксимальныйРазмерФайла() (по умолчанию 50 МБ). Проверяйте его до добавления, а не после падения записи.
  • Вызов служебных модулей. РаботаСФайламиСлужебный и РаботаСФайламиСлужебныйВызовСервера — внутренние. Их состав меняется при обновлении БСП, обращаться к ним из прикладного кода нельзя.

Частые вопросы о присоединённых файлах в БСП

Как получить двоичные данные присоединённого файла в БСП?

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

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

Файл с диска сервера — РаботаСФайлами.ДобавитьФайлСДиска(Владелец, Путь). Данные из памяти — ПоместитьВоВременноеХранилище(), затем ДобавитьФайл() со структурой из ПараметрыДобавленияФайла(). Перед добавлением стоит проверить КОбъектуМожноПрисоединятьФайлы().

Почему ДвоичныеДанныеФайлов возвращает меньше записей, чем передано файлов?

Функция пропускает файлы, недоступные пользователю на чтение, и файлы без двоичных данных, если вызвана с ВызыватьИсключение = Ложь. Результат — это Соответствие, а не массив: перебирайте его циклом либо проверяйте ключ на Неопределено.

Тарифы

ИИ Консоль кода 1С

Лайт

Бесплатно
≈ 1,5 млн токенов

Для ознакомления с возможностями

  • Все функции бесплатно на 2 дня +2 дня за подписку на Telegram или Max
  • Полный набор инструментов без урезаний
  • Без ввода карты
Начать бесплатно

Старт

1990 руб. в месяц
≈ 10 млн токенов

Для индивидуального использования

Выбрать тариф

Продвинутый

Популярный выбор
3990 руб. в месяц
≈ 25 млн токенов

Для интенсивного использования или команд

  • До 15 конфигураций
  • Встроенный агент запросов 1С
  • Свои подписки Codex, Claude и любые OpenAI-совместимые
  • Внешние обработки без Конфигуратора
  • Приоритетная техническая поддержка
Выбрать тариф