При работе в клиент-серверной архитектуре 1С программисты часто сталкиваются с ситуацией, когда стандартные функции работы с файловой системой ведут себя не так, как ожидается. Одной из самых распространенных проблем является использование функции НайтиФайлы(), которая вместо локального диска пользователя начинает обращаться к ресурсам сервера. Рассмотрим подробно, почему это происходит и как правильно реализовать поиск файлов на стороне клиента.
Первым делом проанализируем ситуацию. В 1С:Предприятии 8.3 управляемое приложение разделяет логику на клиентскую и серверную. Если вы вызываете процедуру поиска, крайне важно, в каком контексте она выполняется. Даже если процедура помечена префиксом &НаКлиенте, использование устаревших синхронных методов может приводить к ошибкам или неожиданному поведению.
Важный нюанс: В современных конфигурациях (особенно работающих в режиме совместимости с версией 8.3.5 и выше) в свойствах конфигурации часто установлен параметр "Режим использования синхронных вызовов" в значение "Запретить". Это означает, что привычная функция НайтиФайлы(), которая приостанавливает работу программы до получения результата, на клиенте может просто не сработать. Платформа ожидает от нас использования асинхронных методов.
Для того чтобы гарантированно выполнить поиск на стороне клиента в тонком или веб-клиенте, необходимо использовать метод НачатьПоискФайлов(). Этот метод не блокирует интерфейс и требует создания специальной процедуры-обработчика (оповещения), которая выполнится, когда операционная система вернет список найденных файлов.
Рассмотрим по шагам, как это реализовать. Сначала подготовим основную процедуру, которая инициирует поиск:
&НаКлиенте
Процедура ЗагрузитьФайлыИзКаталога(Команда)
// Подготавливаем путь и маску поиска
ПутьККаталогу = Объект.ПутьККаталогу;
МаскаПоиска = "*.pdf"; // Например, ищем все PDF файлы
// Создаем описание оповещения, которое укажет, какую процедуру вызвать после завершения поиска
// Параметры: ИмяПроцедуры, МодульГдеОнаРасположена, ДополнительныеПараметры
Оповещение = Новый ОписаниеОповещения("ОповещениеФайлыНайдены", ЭтаФорма);
// Запускаем асинхронный поиск
// Параметры: Оповещение, Путь, Маска, Рекурсивно
НачатьПоискФайлов(Оповещение, ПутьККаталогу, МаскаПоиска, Ложь);
КонецПроцедуры
Теперь нам необходимо создать ту самую процедуру ОповещениеФайлыНайдены, которая примет результат поиска. Обратите внимание, что она должна иметь экспортный статус:
&НаКлиенте
Процедура ОповещениеФайлыНайдены(НайденныеФайлы, ДополнительныеПараметры) Экспорт
Если НайденныеФайлы.Количество() = 0 Тогда
Сообщить("В указанном каталоге файлы не найдены.");
Возврат;
КонецЕсли;
Для Каждого Файл Из НайденныеФайлы Цикл
// Здесь мы работаем с объектом типа "Файл" на стороне клиента
Сообщить("Найден файл: " + Файл.Имя + " Размер: " + Файл.Размер());
КонецЦикла;
КонецПроцедуры
Иногда нам не нужно искать список файлов по маске, а достаточно проверить наличие одного конкретного файла. Если мы используем конструкцию Новый Файл(Путь) внутри серверного контекста, система будет искать этот путь на сервере. Чтобы проверить файл на компьютере пользователя, код должен исполняться строго в контексте &НаКлиенте.
Проанализируем пример проверки существования файла:
&НаКлиенте
Функция ПроверитьНаличиеФайлаНаКлиенте(ПолныйПуть)
ЛокальныйФайл = Новый Файл(ПолныйПуть);
Возврат ЛокальныйФайл.Существует();
КонецФункции
Важное предостережение: Никогда не передавайте объект типа Файл с клиента на сервер в качестве параметра процедуры. При пересечении границы "клиент-сервер" объект может потерять связь с реальной файловой системой клиента, и сервер попытается найти его у себя. Если вам нужно передать данные файла на сервер, сначала прочитайте их в ДвоичныеДанные или поместите во временное хранилище.
Если вы применили асинхронные методы, но файлы все равно не находятся в клиент-серверном режиме, разберем типичные ошибки, которые могут возникнуть:
Z:\Files\), помните, что сервер 1С их не видит. Но и клиент может иметь проблемы с доступом, если запущен от имени пользователя с ограниченными правами. Старайтесь использовать полные сетевые пути вида \\ServerName\ShareFolder\.НачатьПодключениеРасширенияРаботыСФайлами() перед началом операций.ПолучитьСписокДоговоров(), помеченные как &НаСервере, непосредственно в момент формирования пути. Если логика поиска случайно "улетает" на сервер, она неминуемо начнет искать файлы в папках сервера (например, в C:\Windows\System32 для службы 1С).Чаще всего поиск файла — это лишь первый шаг. Проанализируем полную цепочку действий: найти файл на клиенте, убедиться, что он существует, и отправить его на сервер для обработки. Это наиболее востребованный сценарий в корпоративных системах.
&НаКлиенте
Процедура НайтиИОтправитьФайл()
Оповещение = Новый ОписаниеОповещения("ЗавершитьПоискДляОтправки", ЭтаФорма);
НачатьПоискФайлов(Оповещение, "C:\MyDocs\", "Contract*.pdf", Ложь);
КонецПроцедуры
&НаКлиенте
Процедура ЗавершитьПоискДляОтправки(РезультатПоиска, ДопПараметры) Экспорт
Если РезультатПоиска.Количество() > 0 Тогда
ФайлОбъект = РезультатПоиска[0];
// Помещаем файл во временное хранилище для передачи на сервер
Описание = Новый ОписаниеПередаваемогоФайла(ФайлОбъект.ПолноеИмя);
МассивФайлов = Новый Массив;
МассивФайлов.Добавить(Описание);
ОповещениеЗагрузки = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтаФорма);
НачатьПомещениеФайлов(ОповещениеЗагрузки, МассивФайлов, , Ложь, УникальныйИдентификатор);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПослеПомещенияФайла(Результат, ДопПараметры) Экспорт
// Здесь 'Результат' содержит адрес во временном хранилище,
// который теперь можно передать в серверную процедуру для обработки.
ОбработатьФайлНаСервере(Результат[0].Хранилище);
КонецПроцедуры
Подводя итог, можно сказать, что главная причина, по которой НайтиФайлы() "ищет на сервере" — это либо выполнение кода в серверном контексте, либо блокировка синхронных вызовов платформой, из-за чего разработчик ошибочно интерпретирует отсутствие результата. Переход на асинхронные методы и контроль контекста исполнения полностью решают эту проблему.