Почему при чтении Excel через ТабличныйДокумент на сервере возникает ошибка «Каталог не обнаружен»?

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

Работа с файлами в клиент-серверной архитектуре «1С:Предприятия» часто преподносит сюрпризы начинающим разработчикам. Ситуация, когда код идеально работает в файловой базе или на локальном компьютере программиста, но «падает» с ошибкой «Каталог не обнаружен» на боевом сервере — одна из самых распространенных. Рассмотрим подробно, почему так происходит, как устроена работа серверных процессов и какими способами можно гарантированно прочитать файл Excel на стороне сервера.

Разберем причину возникновения ошибки

Первое, что нам необходимо понять: в клиент-серверном варианте код, исполняемый под директивой &НаСервере, выполняется не на вашем компьютере и даже не всегда на том сервере, где расположена сама база данных (SQL-сервер). Его исполняет рабочий процесс 1С (rphost.exe). Проблема «Каталог не обнаружен» при выполнении метода ТабличныйДокумент.Прочитать() обычно вызвана одной из трех причин:

  1. Многосерверный кластер: В вашей системе может быть несколько рабочих серверов. Кластер динамически распределяет нагрузку, и сеанс пользователя может запуститься на сервере №2, в то время как файл Excel лежит на диске C: сервера №1. Естественно, сервер №2 «не видит» этот путь.
  2. Контекст службы: Сервер 1С работает как системная служба, чаще всего под специальной учетной записью (например, USR1CV8). У этой учетной записи нет доступа к вашим личным папкам (Рабочий стол, Документы) и, что критично, она не видит подключенные сетевые диски (диск Z:, X: и т.д.), которые вы создали в своем сеансе Windows.
  3. Локальные пути: Переданная в метод строка пути типа "C:\Users\Admin\Desktop\file.xlsx" для сервера означает поиск файла на его собственном локальном диске, а не на диске пользователя, который нажал кнопку в интерфейсе.

Выясним, где именно выполняется код

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


ИмяСервера = ИмяКомпьютера();
Сообщить("Код выполняется на сервере: " + ИмяСервера);

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

Решение 1: Использование UNC-путей (Сетевые шары)

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

  1. Создадим на одном из серверов или файловом хранилище общую папку (например, Exchange).
  2. Настроим доступ к этой папке. Важный момент: права на чтение и запись должны быть даны не только вам, но и той учетной записи, под которой запущен «Агент сервера 1С:Предприятия». Если это локальная учетная запись USR1CV8, ей нужно дать права на уровне NTFS. Если серверы в домене, лучше использовать доменную учетную запись для службы 1С.
  3. В коде всегда указывайте полный сетевой путь в формате UNC:

ПутьКФайлу = "\\ServerName\Exchange\PriceList.xlsx";
ТабДок = Новый ТабличныйДокумент;
Попытка
    ТабДок.Прочитать(ПутьКФайлу);
Исключение
    ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Не удалось прочитать файл: " + ОписаниеОшибки());
КонецПопытки;

Внимание: Никогда не используйте буквы дисков (Z:\...), так как они существуют только в рамках вашей пользовательской сессии и не видны операционной системе в контексте служб.

Решение 2: Передача файла через временное хранилище (Рекомендуемое)

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

Рассмотрим пошагово реализацию этого механизма:

Шаг 1. На клиенте: Используем функцию ПоместитьФайлНаСервер() или ПоместитьФайл().


&НаКлиенте
Процедура ЗагрузитьФайл(Команда)
    
    ОписаниеФайла = Новый ОписаниеПередаваемогоФайла;
    ПередаваемыеФайлы = Новый Массив;
    ПередаваемыеФайлы.Добавить(ОписаниеФайла);
    
    // Вызываем диалог выбора файла
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Диалог.Фильтр = "Excel (*.xlsx)|*.xlsx";
    
    Если Диалог.Выбрать() Тогда
        ПомещенныеФайлы = Новый Массив;
        Если ПоместитьФайлы(,, Диалог.ВыбранныеФайлы, Ложь) Тогда
            // Первый элемент массива содержит адрес во временном хранилище
            ПрочитатьФайлНаСервере(ПомещенныеФайлы[0].Хранилище);
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

Шаг 2. На сервере: Извлекаем данные и читаем их в табличный документ.


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

Проанализируем преимущества этого подхода: нам не важны права доступа к папкам, нам не важны сетевые настройки, и код будет работать даже если завтра ваша база переедет в «облако» или на Linux-сервер.

Проверка доступности программно

Чтобы программа не просто выдавала системную ошибку, а вела себя дружелюбно, мы можем предварительно проверить доступность ресурса. Для этого используем объект Файл. Рассмотрим пример функции-проверки, которую стоит запускать перед чтением:


&НаСервере
Функция ПроверитьДоступностьФайла(ПолныйПуть)
    ПроверкаФайла = Новый Файл(ПолныйПуть);
    Если Не ПроверкаФайла.Существует() Тогда
        Сообщить("Сервер 1С не видит файл по пути: " + ПолныйПуть);
        Сообщить("Текущий рабочий сервер: " + ИмяКомпьютера());
        Возврат Ложь;
    КонецЕсли;
    Возврат Истина;
КонецФункции

Использование такой проверки позволит вам быстро диагностировать проблемы с правами или путями, не прибегая к сложному анализу логов сервера.

Особенности метода Прочитать для разных форматов

Стоит помнить, что ТабличныйДокумент.Прочитать() при работе с Excel (форматы .xls и .xlsx) на сервере не требует установленного Microsoft Excel. Это огромное преимущество, так как использование COM-объектов (Excel.Application) на сервере считается «плохим тоном» и часто блокируется системой безопасности Windows из-за отсутствия интерактивного рабочего стола у системной службы.

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

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

← На главную