Как передать файл с клиента на сервер в 1С:УПП для обработки регламентным заданием?

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

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

Проблема использования временного хранилища

Разберем типичную ситуацию: разработчик помещает файл во временное хранилище на клиенте, получает адрес (строку вида e1cib/tempstorage/...), записывает этот адрес в регистр сведений и пытается прочитать его в регламентном задании. В результате метод ПолучитьИзВременногоХранилища(Адрес) возвращает Неопределено. Выясним причину такого поведения.

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

Способ 1. Передача файла в рамках одного сеанса (Интерактивная работа)

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

На стороне клиента мы выбираем файл и преобразуем его в двоичные данные. Рассмотрим пример кода:


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

На стороне сервера мы извлекаем эти данные и сохраняем их в файловую систему сервера для дальнейших манипуляций:


// Код на сервере
Процедура ОбработатьФайлНаСервере(Адрес)
    Данные = ПолучитьИзВременногоХранилища(Адрес);
    Если Данные <> Неопределено Тогда
        ВременноеИмя = ПолучитьИмяВременногоФайла("pdf");
        Данные.Записать(ВременноеИмя);
        // Далее работаем с файлом по пути ВременноеИмя
    КонецЕсли;
КонецПроцедуры

Способ 2. Передача файла для регламентного задания (через Регистр Сведений)

Когда необходимо, чтобы файл «дождался» запуска регламентного задания (которое работает в другом сеансе), нам нужно физически сохранить его в базу данных. Посмотрим, как это реализовать с помощью регистра сведений и типа ХранилищеЗначения.

Шаг 1. Подготовка регистра. Создадим регистр сведений (например, ОчередьОтправкиФайлов), где одним из ресурсов будет поле ДанныеФайла с типом ХранилищеЗначения.

Шаг 2. Запись данных на клиенте. Проанализируем процесс сохранения файла в этот регистр:


// Обработка на клиенте
ДД = Новый ДвоичныеДанные(ПолноеИмяФайла); // Считываем файл с диска ПК
ХЗ = Новый ХранилищеЗначения(ДД, Новый СжатиеДанных(9)); // Помещаем в объект ХранилищеЗначения

МенеджерЗаписи = РегистрыСведений.ОчередьОтправкиФайлов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период = ТекущаяДата();
МенеджерЗаписи.Идентификатор = Новый УникальныйИдентификатор();
МенеджерЗаписи.ДанныеФайла = ХЗ; // Записываем объект в ресурс регистра
МенеджерЗаписи.Записать();

Шаг 3. Чтение данных в регламентном задании на сервере. Выясним, как извлечь эти данные в другом сеансе:


// Код в модуле регламентного задания
Выборка = РегистрыСведений.ОчередьОтправкиФайлов.Выбрать();
Пока Выборка.Следующий() Цикл
    // Получаем двоичные данные из ХранилищаЗначения
    ДвоичныеДанные = Выборка.ДанныеФайла.Получить();
    
    Если ТипЗнч(ДвоичныеДанные) = Тип("ДвоичныеДанные") Тогда
        ПутьНаСервере = ПолучитьИмяВременногоФайла(".pdf");
        ДвоичныеДанные.Записать(ПутьНаСервере);
        
        // Теперь файл доступен серверу 1С для отправки по почте или обработки
        ОтправитьФайлПоПочте(ПутьНаСервере);
    КонецЕсли;
КонецЦикла;

Важные рекомендации и нюансы

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

  1. Очистка временных файлов: Метод ПолучитьИмяВременногоФайла() только генерирует уникальный путь. После того как вы записали туда данные и использовали их (например, прикрепили к электронному письму), файл необходимо удалить методом УдалитьФайлы(), иначе папка Temp на сервере будет бесконечно раздуваться.
  2. Объем базы данных: Хранение файлов непосредственно в регистре сведений (внутри SQL-базы) существенно увеличивает размер LOB-данных. Если файлов много (сотни в день), это может замедлить создание резервных копий. В таких случаях рекомендуем рассмотреть использование Томов хранения файлов (если в конфигурацию встроена БСП).
  3. Сетевые ресурсы: Если сервер 1С и клиент находятся в одной локальной сети, иногда проще использовать общую сетевую папку (UNC-путь), к которой есть доступ и у пользователя, и у службы usr1cv8. В этом случае достаточно передавать в регистр просто строковый путь к файлу.
  4. Использование БСП: Проверьте, встроена ли в вашу УПП «Библиотека стандартных подсистем». Если да, то для работы с файлами лучше использовать функции общего модуля ФайловаяСистемаКлиент.ЗагрузитьФайл(), которые инкапсулируют в себе все проверки и платформенные особенности.

Подводя итог, можно сказать: для немедленной обработки файла используйте связку ПоместитьВоВременноеХранилище — Адрес — СервернаяПроцедура. Для отложенной обработки регламентным заданием обязательно используйте промежуточное сохранение в базу через ХранилищеЗначения или на общие сетевые диски.

← На главную