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

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

При разработке обработок загрузки данных (например, XML, Excel или CSV) разработчики часто сталкиваются с ситуацией, когда на локальной файловой базе код работает корректно, а в клиент-серверном варианте при запуске через тонкий клиент возникает ошибка: «Файл не найден по указанному пути».

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

Почему возникает ошибка «Файл не найден»?

Проанализируем ситуацию: когда процедура с директивой компиляции &НаСервере пытается открыть файл по переданной строке пути (например, C:\Users\User\Desktop\data.xml), она обращается к файловой системе компьютера, на котором физически работает служба сервера 1С:Предприятия.

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

Рассмотрим основные способы реализации такой передачи.

Способ 1. Передача через временное хранилище с помощью объекта ОписаниеОповещения

Этот способ является классическим для платформы 1С:Предприятие 8.3 при работе в асинхронном режиме интерфейса. Файл с клиентского компьютера помещается во временное хранилище сеанса, после чего на сервере мы извлекаем его и сохраняем во временный каталог для чтения.

Посмотрим на пример реализации:


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

&НаКлиенте
Процедура ПослеВыбораФайла(ПомещенныеФайлы, ДополнительныеПараметры) Экспорт
    
    Если ПомещенныеФайлы = Неопределено Или ПомещенныеФайлы.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;
    
    // Получаем адрес во временном хранилище
    АдресХранилища = ПомещенныеФайлы[0].Хранение;
    Объект.ИмяФайла = ПомещенныеФайлы[0].Имя;
    
    // Вызываем серверную обработку
    ПрочитатьФайлНаСервере(АдресХранилища);
    
КонецПроцедуры

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

Способ 2. Прямая передача объекта ДвоичныеДанные в серверный метод

Объект ДвоичныеДанные сериализуется между контекстами клиента и сервера. Если файл уже выбран или получен на клиенте, мы можем инициализировать ДвоичныеДанные прямо на клиенте и передать их в качестве аргумента процедуры &НаСервере.

Кроме того, для чтения XML нет необходимости обязательно сохранять файл на серверный диск: можно открыть поток чтения в памяти с помощью метода ОткрытьПоток объекта ЧтениеXML.

Разберем подробнее этот сценарий:


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

&НаСервере
Процедура ОбработатьДанныеНаСервере(ДанныеФайла)
    
    // Открываем поток для чтения напрямую из памяти без записи на диск
    Поток = ДанныеФайла.ОткрытьПотокДляЧтения();
    
    Чтение = Новый ЧтениеXML;
    Чтение.ОткрытьПоток(Поток);
    
    Пока Чтение.Прочитать() Цикл
        // Обработка данных XML
    КонецЦикла;
    
    Чтение.Закрыть();
    Поток.Закрыть();
    
КонецПроцедуры

Способ 3. Использование современного асинхронного синтаксиса

Начиная с современных версий платформы 8.3, для повышения читаемости кода рекомендуется использовать асинхронные методы и оператор Ждать вместо создания промежуточных процедур оповещения:


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

Важные практические рекомендации

  1. Управление временными файлами на диске сервера: Если вы используете метод ПолучитьИмяВременногоФайла() и метод Записать(), всегда оборачивайте логику чтения в блок Попытка ... Исключение и удаляйте временный файл методом УдалитьФайлы(), чтобы избежать засорения системного диска сервера.
  2. Привязка временного хранилища: При вызове процедур помещения файлов обязательно передавайте параметр УникальныйИдентификатор текущей формы. Это гарантирует, что данные во временном хранилище будут существовать на протяжении всей жизни формы и не удалятся после первого серверного вызова.
  3. Сетевые пути: Если файл расположен на общем сетевом ресурсе (например, \\server\share\file.xml), служба сервера 1С сможет прочитать его напрямую без предварительной передачи только в том случае, если учетная запись операционной системы, под которой запущена служба ragent/rphost (например, USR1CV8), имеет полные права доступа к этой сетевой папке.
← На главную