Почему возникает ошибка "Каталог не обнаружен" при загрузке Excel файла в 1С и как это исправить?

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

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

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

Анализ ситуации: корень проблемы в клиент-серверной архитектуре

Давайте проанализируем исходный код, который приводит к ошибке. Разработчик пытается прочитать Excel-файл прямо на клиенте после его выбора в диалоге.


&НаКлиенте
Процедура ЗагрузитьФайлСДиска(Команда)
    // ... пропущена проверка ...
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Диалог.Заголовок = "Выбор файла";
    Диалог.Фильтр = "Excel файлы(*.xls;*.xlsx)|*.xls;*.xlsx";

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

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

Текст ошибки выглядит так:

Ошибка при вызове метода контекста (Прочитать) ... по причине: Каталог не обнаружен 'C:\Users\Admin\Downloads\Пример выгузки.xlsx' (подобная ошибка часто встречается, когда настраивается экспорт справочников в Excel).

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

Хотя в коде вызов метода ДанныеExcel.Прочитать(ПутьКЗагрузке) находится в клиентской процедуре, сам метод Прочитать объекта ТабличныйДокумент в управляемых формах для тонкого и веб-клиента выполняется на сервере из соображений безопасности и архитектуры. Платформа пытается найти файл по пути 'C:\Users\Admin\Downloads\...' на жестком диске сервера, а не клиента. Естественно, такого каталога там нет, что и приводит к ошибке.

Правильное решение: передача файла на сервер через временное хранилище

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

Наиболее современным и рекомендуемым способом является асинхронная передача файла. Это означает, что интерфейс пользователя не будет блокироваться (не "зависнет") на время копирования файла, что особенно важно при работе с большими файлами или медленным интернет-соединением.

Разберем этот процесс по шагам.

  1. Шаг 1. На клиенте: инициируем передачу файла

    Вместо стандартного ДиалогВыбораФайла и последующего чтения используем специальный метод НачатьПомещениеФайла. Этот метод сам покажет пользователю диалог выбора файла и начнет его передачу на сервер в фоновом режиме.

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

  2. Шаг 2. На клиенте: обрабатываем результат передачи

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

  3. Шаг 3. На сервере: получаем файл из хранилища и обрабатываем его

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

Практический пример: полный код для загрузки Excel

Теперь давайте перепишем исходный код, используя правильный асинхронный подход.


// &НаКлиенте
// Процедура-инициатор. Вызывается по нажатию кнопки на форме.
Процедура ЗагрузитьИзФайла(Команда)
	
	// Создаем описание оповещения, которое сработает после выбора и передачи файла.
	// Указываем имя процедуры-обработчика: "ЗагрузитьИзФайлаЗавершение".
	Оповещение = Новый ОписаниеОповещения("ЗагрузитьИзФайлаЗавершение", ЭтотОбъект);

	// Используем асинхронный метод для помещения файла на сервер
	НачатьПомещениеФайла(Оповещение, , , Истина, УникальныйИдентификатор);
	
КонецПроцедуры

// &НаКлиенте
// Процедура-обработчик. Вызывается платформой автоматически после завершения операции.
// Экспортная, так как вызывается из оповещения.
Процедура ЗагрузитьИзФайлаЗавершение(Результат, Адрес, ИмяФайла, ДополнительныеПараметры) Экспорт
	
	// Если пользователь отменил выбор файла или произошла ошибка передачи
	Если Не Результат Тогда
		Возврат;
	КонецЕсли;

	// Вызываем серверную процедуру и передаем ей адрес файла во временном хранилище
	// и его исходное имя.
	ПрочитатьФайлНаСервере(Адрес, ИмяФайла);
	
КонецПроцедуры

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

    // После успешного чтения не забываем удалить временный файл
	УдалитьФайлы(ИмяВременногоФайла);
	
	// Теперь в переменной "ТабличныйДокумент" находятся данные из Excel.
	// Можно приступать к их разбору и загрузке в табличную часть документа.
	// Например:
	Объект.ДанныеЗагрузки.Очистить();
	Для Сч = 2 По ТабличныйДокумент.ВысотаТаблицы Цикл // Начинаем со 2-й строки, пропуская заголовок
		НоваяСтрока = Объект.ДанныеЗагрузки.Добавить();
		НоваяСтрока.Артикул = ТабличныйДокумент.Область(Сч, 1).Текст;
		НоваяСтрока.Наименование = ТабличныйДокумент.Область(Сч, 2).Текст;
		НоваяСтрока.Количество = Число(ТабличныйДокумент.Область(Сч, 3).Текст);
	КонецЦикла;
	
	Модифицированность = Истина;
	
КонецПроцедуры

// &НаСервереБезКонтекста
// Вспомогательная функция для получения расширения из имени файла.
Функция РасширениеИзИмениФайла(ИмяФайла)
	Возврат Сред(ИмяФайла, Найти(ИмяФайла, ".") + 1);
КонецФункции

Подведем итог

Чтобы избежать ошибки "Каталог не обнаружен" и корректно организовать работу с файлами в клиент-серверном режиме, всегда следуйте этому правилу:

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

Использование асинхронных методов, таких как НачатьПомещениеФайла, является современной и рекомендуемой практикой, которая обеспечивает отзывчивость интерфейса и корректную работу в любых режимах клиента, включая веб-клиент.

← На главную