Почему фоновое задание не видит файл, созданный на клиенте, и как правильно организовать выгрузку данных?

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

При работе в клиент-серверном варианте 1С:Предприятие начинающие (и не только) разработчики часто сталкиваются с ошибкой "Файл не обнаружен" при попытке обработать файл внутри фонового задания. Ситуация кажется парадоксальной: код создания файла отработал без ошибок, файл физически существует на диске, но ФоновоеЗадание упорно его "не видит".

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

Разбор причины: Путаница контекстов клиент-сервер

Рассмотрим стандартную ситуацию: пользователь работает в Толстом клиенте (обычное приложение). Процедура выгрузки запускается в контексте клиента. Она создает временный файл в каталоге, который возвращает функция КаталогВременныхФайлов(). На локальной машине пользователя это может быть путь вида C:\Users\ИмяПользователя\AppData\Local\Temp\....

Затем инициируется фоновое задание через метод ФоновыеЗадания.Выполнить(). Важно помнить: фоновое задание всегда выполняется на сервере 1С под учетной записью, от имени которой запущена служба сервера (например, USR1CV8).

Проанализируем, почему сервер не находит файл:

  1. Разные физические машины: Если сервер 1С и клиентский компьютер — это разные узлы сети, то путь C:\Temp для них означает совершенно разные физические папки на разных жестких дисках.
  2. Разные профили пользователей: Даже если всё происходит на одном сервере (например, в терминальной сессии), КаталогВременныхФайлов() для пользователя и для службы сервера 1С — это разные директории, защищенные правами доступа операционной системы.
  3. Отсутствие прав: Учетная запись службы сервера 1С часто не имеет прав на чтение личных папок пользователей.

Анализ исходного (проблемного) кода

Посмотрим на пример кода, который вызывает ошибку. Здесь автор пытается передать путь к файлу в фоновое задание:


Процедура ВыгрузитьОбъектВXML(Объект, ИмяФайла, МассивПапок) Экспорт 
    ПолноеИмяФайла = КаталогВременныхФайлов() + ИмяФайла; 
    ЗаписьXML = Новый ЗаписьXML; 
    ЗаписьXML.ОткрытьФайл(ПолноеИмяФайла); 
    // ... запись объекта в XML ...
    ЗаписьXML.Закрыть(); 

    МассивПараметров = Новый Массив;
    МассивПараметров.Добавить(ПапкаВыгрузки);
    МассивПараметров.Добавить(ИмяФайла);
    МассивПараметров.Добавить(ПолноеИмяФайла); // Передаем путь
    
    // Фоновое задание не найдет этот файл!
    Задание = ФоновыеЗадания.Выполнить("МодульТест.СкопироватьФайлВКаталог", МассивПараметров); 
КонецПроцедуры

Ошибка "Файл не обнаружен" здесь закономерна, так как процедура СкопироватьФайлВКаталог, исполняясь на сервере, пытается обратиться к локальному диску клиента.

Решение №1: Передача данных через строку (сериализация)

Если объем передаваемых данных невелик (например, один объект номенклатуры или контрагента), самым простым и надежным решением будет отказаться от промежуточного файла. Вместо этого мы можем сериализовать объект в XML-строку и передать эту строку непосредственно в параметрах фонового задания.

Разберем обновленный алгоритм:

  1. На стороне инициатора (клиента или основного серверного потока) формируем XML-строку.
  2. Передаем эту строку в массив параметров метода ФоновыеЗадания.Выполнить().
  3. Внутри фонового задания записываем эту строку в файл уже в контексте сервера.

Посмотрим на реализацию этого подхода:


Процедура ВыгрузитьОбъектВXML(Объект, ИмяФайла, МассивПапок) Экспорт 
    // Сериализуем объект в строку вместо файла
    ЗаписьXML = Новый ЗаписьXML; 
    ЗаписьXML.УстановитьСтроку(); 
    СериализаторXDTO.ЗаписатьXML(ЗаписьXML, Объект, НазначениеТипаXML.Явное); 
    ОбъектСтрокой = ЗаписьXML.Закрыть(); 

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

// Процедура, выполняемая в фоновом задании на сервере
Процедура СоздатьФайлНаСервере(ПапкаВыгрузки, ИмяФайла, ОбъектСтрокой) Экспорт 
    // На сервере путь к папке должен быть доступен службе 1С (UNC-путь или локальный путь сервера)
    Текст = Новый ЗаписьТекста(ПапкаВыгрузки + "\" + ИмяФайла, КодировкаТекста.UTF8); 
    Текст.Записать(ОбъектСтрокой); 
    Текст.Закрыть(); 
КонецПроцедуры

Решение №2: Использование Временного хранилища

Если объект большой и передача его через строку параметров замедляет систему, следует использовать Временное хранилище. Это "мостик" между клиентом и сервером.

Алгоритм действий следующий:

  1. Помещаем данные во временное хранилище: Адрес = ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор).
  2. Передаем Адрес в фоновое задание.
  3. Внутри фонового задания извлекаем данные: Данные = ПолучитьИзВременногоХранилища(Адрес).

Важный нюанс: Чтобы данные во временном хранилище были доступны фоновому заданию, при вызове ПоместитьВоВременноеХранилище нужно передать УникальныйИдентификатор именно того фонового задания, которое будет их использовать, либо использовать идентификатор формы (если вызов с клиента).

Особенности отладки фоновых заданий

Многие разработчики жалуются, что точка останова в процедуре фонового задания не срабатывает. Выясним, как настроить отладку правильно:

Проблема транзакций и событий "При записи"

Проанализируем ситуацию, когда фоновое задание запускается в модуле объекта внутри события ПриЗаписи. Это опасный момент. Вся запись объекта происходит внутри транзакции базы данных.

Помните: фоновое задание, запущенное внутри транзакции, не начнет выполняться реально, пока транзакция основного сеанса не будет успешно завершена (зафиксирована). Если в коде после запуска фонового задания произойдет ошибка и транзакция откатится, фоновое задание будет отменено системой. Если же фоновому заданию нужно прочитать данные того же объекта из базы, оно может увидеть их старое состояние, если транзакция еще не "отпустила" блокировки.

Рекомендации по работе с файлами и путями

Чтобы ваш код был универсальным и не зависел от операционной системы, придерживайтесь следующих правил:

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

← На главную