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

Программист 1С v8.3 (Управляемые формы) 1С:Документооборот IT и автоматизация бизнеса
← На главную

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

Постановка задачи и выбор инструментов

Представим ситуацию: нам необходимо выбрать список документов за определенный период и выгрузить все связанные с ними файлы в каталог на диске D:\Выгрузка\. При этом важно сохранить структуру: каждый файл должен лежать в подпапке, имя которой соответствует коду документа — для этого подойдёт инструмент массовой выгрузки файлов из 1С:Документооборот со структурой папок. Для решения мы будем использовать асинхронный метод платформы НачатьПолучениеФайловССервера и объекты ОписаниеПередаваемогоФайла.

Реализация серверной части: подготовка данных

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

Проанализируем следующий алгоритм:

  1. Выполняем запрос к справочнику документов для получения ссылок.
  2. Для каждого документа находим все подчиненные файлы (используя методы БСП).
  3. Получаем ДвоичныеДанные каждого файла.
  4. Помещаем эти данные во временное хранилище.
  5. Формируем объект ОписаниеПередаваемогоФайла, где указываем путь сохранения (включая имя подкаталога) и адрес во временном хранилище.

&НаСервере
Функция СписокДокументовДляВыгрузки() Экспорт
    
    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    |	ВнутренниеДокументы.Ссылка КАК Ссылка,
    |	ВнутренниеДокументы.Код КАК Код
    |ИЗ
    |	Справочник.ВнутренниеДокументы КАК ВнутренниеДокументы
    |ГДЕ
    |	ВнутренниеДокументы.ДатаРегистрации МЕЖДУ &ДатаС И &ДатаПо";    
    
    Запрос.УстановитьПараметр("ДатаС", ЭтаФорма.ДатаНачала);
    Запрос.УстановитьПараметр("ДатаПо", ЭтаФорма.ДатаКонца);
    
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    МассивВыгружаемыхФайлов = Новый Массив;
        
    Пока Выборка.Следующий() Цикл

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

Реализация клиентской части: получение файлов

На клиенте нам остается только вызвать метод НачатьПолучениеФайловССервера — для этого есть обработка массовой выгрузки присоединенных файлов из 1С. Этот метод хорош тем, что он выполняет операцию асинхронно, не блокируя интерфейс программы (в случае большого объема данных это критично). Выясним, как выглядит процедура вызова.


&НаКлиенте
Процедура Выгрузить(Команда)
     
     // Путь к базовому каталогу выгрузки
     КаталогВыгрузки = "D:\Выгрузка\";
     
     // Получаем подготовленный массив описаний с сервера
     СписокФайловДляПолучения = СписокДокументовДляВыгрузки();
     
     // Параметры метода:
     // 1. Описание оповещения (для обработки завершения)
     // 2. Массив объектов ОписаниеПередаваемогоФайла
     // 3. Целевой каталог на клиенте
     НачатьПолучениеФайловССервера(Неопределено, СписокФайловДляПолучения, КаталогВыгрузки);
     
КонецПроцедуры

Важные нюансы и оптимизация

Рассмотрим подробнее несколько критических моментов, которые могут повлиять на стабильность работы данного решения:

1. Обработка недопустимых символов. Имена файлов в 1С могут содержать символы, которые запрещены в Windows (например, кавычки или двоеточия). Если попытаться сохранить файл с таким именем напрямую, система выдаст ошибку. Мы использовали ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла — это обязательный шаг при формировании пути.

2. Память сервера. При использовании ПоместитьВоВременноеХранилище данные физически копируются в оперативную память сервера (или в кэш). Если файлов тысячи и они весят по 100 Мб, вы рискуете вызвать аварийное завершение рабочего процесса rphost. В таких случаях рассмотрим альтернативный вариант: упаковку всех файлов в один ZIP-архив на сервере и передачу одного файла архива на клиент.

3. Работа в веб-клиенте. Если ваши пользователи работают через браузер, массовое скачивание файлов может быть заблокировано настройками безопасности браузера. В этом случае упаковка в ZIP становится не просто рекомендацией, а единственным надежным способом выгрузки.

4. Асинхронность. В примере выше в метод НачатьПолучениеФайловССервера первым параметром передано Неопределено. Это допустимо, но для качественного UX (пользовательского опыта) лучше передать ОписаниеОповещения. Это позволит вывести сообщение «Выгрузка завершена» или обработать ситуацию, когда у пользователя не хватило прав на запись в папку D:\Выгрузка\. Такой подход является классическим примером использования механизма длительных операций в БСП.

Пример использования ZIP-архива для больших объемов

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


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

Таким образом, мы выяснили, что для решения задачи выгрузки идеально подходит связка ОписаниеПередаваемогоФайла и НачатьПолучениеФайловССервера. Это стандартный и наиболее эффективный путь в среде управляемых форм 1С. Для более универсальных сценариев существуют и готовые обработки для копирования файлов и каталогов между клиентом и сервером, такие как экспорт вложений и изображений номенклатуры во внешние файлы.

← На главную