При разработке внешних обработок и интеграционных механизмов часто возникает задача пакетного или одиночного сохранения присоединенных файлов (например, фотографий контрагентов, сканов документов или карточек) из базы 1С в заданную папку на жестком диске. Разберем различные способы решения этой задачи в зависимости от архитектуры хранения файлов в конфигурации.
Проанализируем структуру хранения данных. В большинстве конфигураций на платформе 1С:Предприятие 8.3 для работы с изображениями и документами используется подсистема работы с файлами. При этом физически двоичные данные могут находиться либо непосредственно в таблицах базы данных (в реквизите с типом ХранилищеЗначения), либо во внешних томах на диске.
Рассмотрим штатный механизм, используемый в конфигурациях с БСП или аналогичными библиотеками работы с файлами. При вызове серверной функции РаботаСФайламиВызовСервера.ПолучитьДанныеФайлаДляСохранения() формируется структура параметров файла, содержащая адрес во временном хранилище и метаинформацию о файле (имя, расширение).
Разберем по шагам, как извлечь двоичные данные по полученной навигационной ссылке и записать их в файл на клиенте или сервере:
// Пример программной выгрузки файла через структуру ДанныеФайла
Если ЗначениеЗаполнено(Контрагент.ФайлКартинки) Тогда
// Получаем структуру с описанием файла и ссылкой на временное хранилище
ДанныеФайла = РаботаСФайламиВызовСервера.ПолучитьДанныеФайлаДляСохранения(Контрагент.ФайлКартинки, Неопределено, Неопределено);
Если ДанныеФайла <> Неопределено И ЗначениеЗаполнено(ДанныеФайла.СсылкаНаДвоичныеДанныеФайла) Тогда
// Извлекаем двоичные данные из временного хранилища
ДвоичныеДанные = ПолучитьИзВременногоХранилища(ДанныеФайла.СсылкаНаДвоичныеДанныеФайла);
Если ТипЗнч(ДвоичныеДанные) = Тип("ДвоичныеДанные") Тогда
// Формируем целевой путь к файлу на диске
ИмяФайла = Контрагент.Наименование + "." + ДанныеФайла.Расширение;
ПолныйПуть = ПутьДляКартинок + "\" + ИмяФайла;
// Записываем файл на диск
ДвоичныеДанные.Записать(ПолныйПуть);
КонецЕсли;
КонецЕсли;
КонецЕсли;
Посмотрим на ситуацию, когда требуется выполнить пакетную выгрузку фотографий в фоновом режиме или в рамках серверной процедуры без использования клиентских контекстов и промежуточных временных хранилищ. Если данные хранятся в самой информационной базе, мы можем напрямую обратиться к реквизиту ФайлХранилище объекта файла или его версии.
Разберем пример серверного кода для чтения двоичных данных из справочника:
&НаСервере
Процедура СохранитьФотоКонтрагентаНаСервере(СсылкаНаКонтрагента, КаталогВыгрузки)
// Проверяем заполненность ссылки на файл картинки
Если НЕ ЗначениеЗаполнено(СсылкаНаКонтрагента.ФайлКартинки) Тогда
Возврат;
КонецЕсли;
ОбъектФайла = СсылкаНаКонтрагента.ФайлКартинки;
// В зависимости от структуры метаданных хранилище может находиться в самом файле или в справочнике версий
Хранилище = Неопределено;
Расширение = "png";
// Вариант 1: прямое хранение в реквизите файла
Если ОбщегоНазначенияКлиентСервер.ЕстьРеквизитИлиСвойствоОбъекта(ОбъектФайла, "ФайлХранилище") Тогда
Хранилище = ОбъектФайла.ФайлХранилище;
// Вариант 2: хранение через реквизит ТекущаяВерсия
ИначеЕсли ОбщегоНазначенияКлиентСервер.ЕстьРеквизитИлиСвойствоОбъекта(ОбъектФайла, "ТекущаяВерсия")
И ЗначениеЗаполнено(ОбъектФайла.ТекущаяВерсия) Тогда
Хранилище = ОбъектФайла.ТекущаяВерсия.ФайлХранилище;
Расширение = ОбъектФайла.ТекущаяВерсия.Расширение;
КонецЕсли;
Если Хранилище <> Неопределено Тогда
ДвоичныеДанные = Хранилище.Получить();
Если ТипЗнч(ДвоичныеДанные) = Тип("ДвоичныеДанные") Тогда
// Очищаем наименование от запрещенных символов файловой системы
ИмяБезСпецСимволов = СсылкаНаКонтрагента.Наименование;
ЗапрещенныеСимволы = "\/:*?""<>|";
Для Сч = 1 По СтрДлина(ЗапрещенныеСимволы) Цикл
Символ = Сред(ЗапрещенныеСимволы, Сч, 1);
ИмяБезСпецСимволов = СтрЗаменить(ИмяБезСпецСимволов, Символ, "_");
КонецЦикла;
ИмяФайла = ИмяБезСпецСимволов + "." + Расширение;
ПолныйПутьКФайлу = КаталогВыгрузки + "\" + ИмяФайла;
ДвоичныеДанные.Записать(ПолныйПутьКФайлу);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Выясним причину, по которой метод Хранилище.Получить() может возвращать Неопределено. Это происходит в тех случаях, когда в базе включено хранение файлов в томах на диске. В этой ситуации бинарное содержимое не дублируется в таблицах базы данных, а реквизит ФайлХранилище остается пустым.
Для сохранения файла из тома выполним следующие действия:
Том (ссылка на справочник томов хранения) и относительный путь к файлу (например, ПутьКФайлу или ПолноеИмяФайлаВТоме).КопироватьФайл() или считываем его в объект ДвоичныеДанные.
// Пример извлечения файла, хранящегося в томе
ИсходныйПуть = ОбъектФайла.Том.ПолныйПутьWindows + ОбъектФайла.ПутьКФайлу;
ЦелевойПуть = КаталогВыгрузки + "\" + Контрагент.Наименование + "." + ОбъектФайла.Расширение;
Если НайтиФайлы(ИсходныйПуть).Количество() > 0 Тогда
КопироватьФайл(ИсходныйПуть, ЦелевойПуть);
КонецЕсли;
Рассмотрим ключевые нюансы, на которые следует обратить внимание при разработке обработки:
ДвоичныеДанные.Записать() на сервере сохранит файл на сервере 1С, а не на локальном компьютере пользователя. Для выгрузки на ПК клиента двоичные данные необходимо передавать на сторону клиента через временное хранилище.Файл и метод СоздатьКаталог().