Работа с присоединенными файлами в конфигурациях, построенных на базе Библиотеки стандартных подсистем (БСП), существенно отличается от манипуляций с обычными справочниками. Это связано с тем, что БСП берет на себя управление хранением (в базе или в томах на диске), версионированием и правами доступа. Рассмотрим типичную задачу: необходимо найти все сканы накладных, прикрепленные к документам ПриходМатериалов, ориентируясь на строковый номер накладной, и выгрузить эти файлы в определенную папку на диске.
Прежде чем приступать к написанию кода, проанализируем, как БСП организует хранение. Для каждого объекта (например, документа), к которому подключена работа с файлами, в системе обычно создается отдельный справочник с суффиксом ...ПрисоединенныеФайлы. Однако в некоторых внедрениях может использоваться и общий справочник Файлы.
Важно понимать, что сами двоичные данные (содержимое PDF или картинки) не хранятся в основной таблице справочника. Они могут находиться либо в регистре сведений ДвоичныеДанныеФайлов, либо в специализированных томах на сервере. Поэтому мы никогда не обращаемся к данным напрямую через Выборка.РеквизитХранилище, а всегда используем программный интерфейс модуля РаботаСФайлами. Для оптимизации занимаемого на диске или в СУБД места при массовом импорте сканов можно применить решение для автоматического сжатия изображений в конфигурациях на БСП.
Рассмотрим ситуацию, когда у нас есть массив номеров накладных, полученный из табличной части другого документа. Нам нужно найти документы-владельцы и их файлы. Главная ошибка новичков — выполнение запросов в цикле. Проанализируем, как сделать это правильно с помощью одного запроса и внутреннего соединения.
Допустим, мы уже выгрузили список нужных номеров накладных в массив НомераНакладных. Теперь составим запрос к справочнику файлов, который связан с нашим документом. Выясним причину, по которой поиск может не давать результатов: часто реквизит связи называется ВладелецФайла, и он должен указывать на ссылку документа ПриходМатериалов.
// Подготовим номера накладных (из табличной части объекта)
ТЗ_Номера = Объект.СоставНакладных.Выгрузить(,"НомерНакладной");
ТЗ_Номера.Свернуть("НомерНакладной");
МассивНомеров = ТЗ_Номера.ВыгрузитьКолонку("НомерНакладной");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Файлы.Ссылка КАК ФайлСсылка,
| Файлы.Наименование КАК ИмяФайла,
| Файлы.Расширение КАК Расширение,
| Файлы.ТекущаяВерсия КАК ТекущаяВерсия
|ИЗ
| Справочник.ПриходМатериаловПрисоединенныеФайлы КАК Файлы
|ГДЕ
| Файлы.ВладелецФайла.НомерНакладной В (&МассивНомеров)
| И НЕ Файлы.ПометкаУдаления";
Запрос.УстановитьПараметр("МассивНомеров", МассивНомеров);
РезультатЗапроса = Запрос.Выполнить();
Обратите внимание: мы обращаемся к Файлы.ВладелецФайла.НомерНакладной. Это допустимо, если ВладелецФайла имеет строго определенный тип. Если же тип составной, лучше использовать ВНУТРЕННЕЕ СОЕДИНЕНИЕ с таблицей документа.
После того как мы получили ссылки на файлы, нам необходимо извлечь их содержимое. Рассмотрим использование метода РаботаСФайлами.ДвоичныеДанныеФайла. Этот метод универсален: он сам определит, лежит ли файл в томе на диске или в информационной базе, и вернет объект ДвоичныеДанные.
Проанализируем нюанс с версионированием. В БСП файлы могут иметь несколько версий. Реквизит ТекущаяВерсия справочника файлов указывает на самый актуальный вариант документа. Хотя метод ДвоичныеДанныеФайла часто принимает и ссылку на сам файл, надежнее передавать в него именно ссылку на версию.
Выборка = РезультатЗапроса.Выбрать();
КаталогВыгрузки = "C:\123\"; // Путь на сервере!
Пока Выборка.Следующий() Цикл
// Получаем двоичные данные актуальной версии файла
ДвоичныеДанные = РаботаСФайлами.ДвоичныеДанныеФайла(Выборка.ФайлСсылка, Ложь);
Если ДвоичныеДанные = Неопределено Тогда
Сообщить(СтрШаблон("Не удалось получить данные для файла: %1", Выборка.ИмяФайла));
Продолжить;
КонецЕсли;
// Формируем полное имя файла.
// Важно: расширение в БСП хранится без точки, добавляем её вручную.
ПолноеИмяФайла = КаталогВыгрузки + Выборка.ИмяФайла + "." + Выборка.Расширение;
Попытка
ДвоичныеДанные.Записать(ПолноеИмяФайла);
Исключение
Сообщить(СтрШаблон("Ошибка записи на диск: %1. Проверьте права доступа к папке.", ОписаниеОшибки()));
КонецПопытки;
КонецЦикла;
При работе с этим кодом необходимо учитывать несколько критических факторов, которые могут привести к ошибкам в промышленной эксплуатации:
ДвоичныеДанные.Записать() в серверном коде, файл будет сохранен на диске сервера. Если пользователь ожидает увидеть файл на своем рабочем столе, этот подход не сработает. В таком случае файлы нужно передавать на клиент и использовать ФайловаяСистемаКлиент.СохранитьФайл() или методы БСП из модуля РаботаСФайламиКлиент.ПриходМатериалов, запрос к справочнику файлов вернет пустой результат (из-за механизмов RLS).Наименование) может содержать символы, недопустимые в операционной системе (например, слэши или двоеточия). Перед записью на диск рекомендуется "очищать" строку наименования.Если вам не нужно делать сложный поиск по реквизитам, а требуется просто получить все файлы конкретного документа, БСП предоставляет более простой программный интерфейс. Разберем пример, как получить список файлов, зная ссылку на документ:
СписокФайлов = РаботаСФайлами.ПрисоединенныеФайлыОбъекта(СсылкаНаДокумент);
Для Каждого ФайлСсылка Из СписокФайлов Цикл
Данные = РаботаСФайлами.ДанныеФайла(ФайлСсылка);
// Данные — это структура с информацией о файле (имя, расширение, ссылка на версию)
// Далее получаем ДвоичныеДанные и сохраняем
КонецЦикла;
Этот метод предпочтительнее, так как он инкапсулирует в себе логику запросов к базе и гарантирует получение корректного набора данных согласно настройкам БСП.
Если код отрабатывает без ошибок, но РаботаСФайлами.ДвоичныеДанныеФайла возвращает Неопределено, проанализируем ситуацию:
ТекущаяВерсия в справочнике файлов. Если он пуст, значит, карточка файла создана, а сами данные не были загружены.Используя предложенные методы и учитывая нюансы клиент-серверного взаимодействия, вы сможете эффективно автоматизировать сбор и выгрузку любой документации, хранящейся в вашей системе на базе БСП. Для быстрого поиска готовых решений при работе с программным API библиотеки можно использовать интерактивный справочник по методам БСП с примерами кода.