При переносе рабочего кода из обычной внешней обработки в регламентное или фоновое задание разработчики часто сталкиваются с неприятным исключением: «Ошибка при вызове метода контекста (ОткрытьФайл) по причине: Каталог не обнаружен...». При этом на локальном компьютере пользователя этот же код отрабатывает абсолютно корректно и без ошибок. В этой статье мы подробно разберем по шагам, почему возникает данная проблема в клиент-серверной архитектуре «1С:Предприятия», и рассмотрим лучшие практики по ее устранению.
Главная причина кроется в месте выполнения вашего программного кода. Когда вы запускаете обработку интерактивно (в режиме тонкого или толстого клиента), код выполняется непосредственно на вашем локальном компьютере. Если в коде указан путь вида D:\MyFile.xml, система ищет этот диск и файл на вашем локальном жестком диске.
Регламентные и фоновые задания работают совершенно иначе:
rphost).D: не на вашем компьютере, а на физическом сервере, где установлена служба 1C:Enterprise Server Agent.D: или на нем нет папки, указанной в пути, платформа мгновенно генерирует ошибку «Каталог не обнаружен».Даже если на физическом сервере 1С существует нужный диск и папка, запись файла может завершиться ошибкой. Рассмотрим, почему это происходит:
USR1CV8, USR1CV82 или USR1CV83).USR1CV8 должны быть явно настроены права на «Запись» и «Изменение» (Write / Modify) для целевой папки на уровне операционной системы.Посмотрим на ситуацию, когда разработчик пытается обойти ограничение локального диска и указывает в коде путь к общему сетевому ресурсу, например: \\StorageServer\ShareFolder\MyFile.xml. Здесь также есть важный подводный камень:
Поскольку учетная запись сервера USR1CV8 является локальной, она не имеет доступа к сети предприятия. Сетевая папка, даже если к ней открыт доступ «Для всех», отклонит запрос на запись от неавторизованного локального пользователя другого сервера.
Для решения этой проблемы мы можем порекомендовать два пути:
DOMAIN\Service_1C). Этой учетной записи необходимо предоставить полные права на чтение и запись в целевую сетевую папку.USR1CV8 и точно самым паролем, как на сервере 1С, и предоставить ему соответствующие права на доступ к папке.Если файл создается исключительно для временного хранения (например, для последующей отправки по электронной почте, выгрузки на FTP или отправки через API-интеграцию), лучшим решением будет использование механизма временных файлов 1С.
Рассмотрим пример кода, который гарантированно отработает без ошибок прав доступа, поскольку временные файлы создаются в системной временной папке сервера 1С, к которой у службы сервера всегда есть полные права:
// Получаем уникальное имя временного файла на сервере
ПутьКФайлу = ПолучитьИмяВременногоФайла("xml");
// Инициализируем запись XML
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПутьКФайлу, "utf-8");
// ... Здесь выполняется логика записи ваших данных в XML ...
ЗаписьXML.Закрыть();
// Выполняем целевое действие с файлом (например, отправка)
ОтправитьФайлПолучателю(ПутьКФайлу);
// Обязательно удаляем временный файл после использования, чтобы не засорять диск сервера
Попытка
УдалитьФайлы(ПутьКФайлу);
Исключение
ЗаписьЖурналаРегистрации("ОбменДанными", УровеньЖурналаРегистрации.Предупреждение, , , "Не удалось удалить временный файл: " + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
В обсуждении на форуме автор упомянул, что файл на диске нужен ему «для просмотра потом», чтобы контролировать, какие именно данные выгрузились. Запись файлов напрямую на жесткие диски сервера является плохим тоном разработки. Гораздо надежнее хранить такие файлы внутри информационной базы 1С.
Проанализируем, как это реализовать:
Справочник.ЛогиВыгрузки или используйте стандартный механизм присоединенных файлов из Библиотеки Стандартных Подсистем). В справочнике должен быть реквизит с типом ХранилищеЗначения.ДвоичныеДанные и поместите его в справочник.Посмотрим на пример кода для реализации этой схемы:
ПутьКФайлу = ПолучитьИмяВременногоФайла("xml");
// Записываем данные
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПутьКФайлу, "utf-8");
// Код выгрузки...
ЗаписьXML.Закрыть();
// Читаем файл в двоичные данные
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
// Сохраняем в информационную базу
НовыйЛог = Справочники.ЛогиВыгрузки.СоздатьЭлемент();
НовыйЛог.Наименование = "Выгрузка от " + Формат(ТекущаяДата(), "ДФ=dd.MM.yyyy_HH.mm.ss");
НовыйЛог.ДанныеФайла = Новый ХранилищеЗначения(ДвоичныеДанныеФайла, Новый СжатиеДанных(9));
НовыйЛог.Записать();
// Удаляем временный файл с диска
УдалитьФайлы(ПутьКФайлу);
При таком подходе любой ответственный пользователь или администратор сможет открыть этот элемент справочника прямо в режиме 1С:Предприятие, просмотреть лог или сохранить XML-файл на свой локальный компьютер для детального анализа.
Чтобы быстро локализовать подобные ошибки и не гадать, почему фоновое задание ведет себя не так, как обычная обработка, настройте серверную отладку:
-debug для протокола TCP/IP или -http для HTTP-отладки).