При разработке механизмов загрузки данных из внешних источников программисты часто сталкиваются с необходимостью программного перебора файлов в определенной папке. В системе 1С:Предприятие 8 для этого предназначена встроенная функция НайтиФайлы(). Однако иногда возникает ситуация, когда вместо ожидаемого массива файлов функция возвращает массив с единственным элементом, который описывает сам каталог. В этой статье мы подробно разберем, почему так происходит, и как правильно настроить поиск файлов.
Рассмотрим пример кода, в котором возникла проблема. Разработчик пытается получить список всех файлов в каталоге, передавая в функцию только путь к этому каталогу:
&НаКлиенте
Процедура ЗаполнитьИзФайловXLS(Команда)
// ПутьККаталогу содержит строку, например, "C:\MyFiles"
МассивНайденных = НайтиФайлы(ЭтотОбъект.ПутьККаталогу);
Для Каждого Файл из МассивНайденных Цикл
ЗаполнитьИзФайловXLSНаСервере(Файл.ИмяФайла);
КонецЦикла;
КонецПроцедуры
Проанализируем поведение системы в данном случае. Согласно синтаксису платформы, функция НайтиФайлы() принимает три параметра: Путь, Маска и ИскатьВПодкаталогах. Если мы передаем только первый параметр, система интерпретирует его буквально. Если путь указан без завершающего разделителя и без маски, 1С считает, что нас интересует информация о самом объекте файловой системы (в данном случае — о папке). Поэтому в массив попадает один объект типа Файл, указывающий на сам каталог.
Чтобы функция вернула содержимое каталога, необходимо явно указать Маску. Рассмотрим исправленный вариант кода, где мы ищем только файлы электронных таблиц с расширением .xls:
// Правильное использование с указанием маски
МассивНайденных = НайтиФайлы(ЭтотОбъект.ПутьККаталогу, "*.xls");
Если нам требуется получить абсолютно все файлы и вложенные папки, содержащиеся в каталоге, мы можем использовать универсальную маску * или *.*. Важно понимать разницу:
*.* — возвращаются все файлы, имеющие расширение.* — возвращаются все файлы и все вложенные папки.Выясним, как отличить файлы от папок, если мы получили смешанный массив. Объект типа Файл обладает набором полезных методов, которые позволяют уточнить тип найденного объекта. Проанализируем пример кода с дополнительной проверкой:
МассивНайденных = НайтиФайлы(ЭтотОбъект.ПутьККаталогу, "*");
Для Каждого ТекущийОбъект из МассивНайденных Цикл
Если ТекущийОбъект.ЭтоФайл() Тогда
// Обрабатываем только файлы
Сообщить("Найден файл: " + ТекущийОбъект.ПолноеИмя);
ИначеЕсли ТекущийОбъект.ЭтоКаталог() Тогда
// Пропускаем или обрабатываем вложенные папки
Сообщить("Найдена папка: " + ТекущийОбъект.Имя);
КонецЕсли;
КонецЦикла;
Помимо типа объекта, мы можем использовать метод Размер() для исключения пустых файлов или ПолучитьВремяИзменения(), чтобы обрабатывать только самые свежие документы.
Разберем важный нюанс работы в современных версиях платформы (8.3.15 и выше). При работе в тонком или веб-клиенте использование синхронного метода НайтиФайлы() может привести к блокировке интерфейса или ошибкам безопасности в браузере. В таких случаях настоятельно рекомендуется использовать асинхронный аналог — НайтиФайлыАсинх().
Этот метод работает через механизм "Обещаний" (Promises). Посмотрим, как может выглядеть современная реализация:
&НаКлиенте
Асинх Процедура ЗаполнитьИзФайловXLSАсинх(Команда)
МассивНайденных = Ждать НайтиФайлыАсинх(ЭтотОбъект.ПутьККаталогу, "*.xls");
Для Каждого Файл из МассивНайденных Цикл
// Дальнейшая логика обработки
КонецЦикла;
КонецПроцедуры
Важно: Для работы с локальными файлами пользователя в веб-клиенте обязательно должно быть установлено расширение работы с файлами.
Если ваша база 1С работает на сервере под управлением Linux, следует учитывать регистрозависимость файловой системы. Рассмотрим основные отличия:
*.XLS и *.xls найдут одни и те же файлы. В Linux файл Report.XLS не будет найден по маске *.xls. В таких случаях лучше программно обрабатывать массив или учитывать возможные варианты расширений./, и обратный \ слэш, хорошим тоном считается использование функции ПолучитьРазделительПути() при формировании строк.rphost. Убедитесь, что у этого пользователя есть права доступа к целевому каталогу, иначе функция вернет пустой массив.Иногда файлы могут быть распределены по разным папкам внутри основного каталога. Чтобы не писать сложные рекурсивные алгоритмы самостоятельно, воспользуемся третьим параметром функции НайтиФайлы(). Установим параметр ИскатьВПодкаталогах в значение Истина:
// Поиск во всех вложенных папках
МассивНайденных = НайтиФайлы(ЭтотОбъект.ПутьККаталогу, "*.xls", Истина);
В этом случае в массив попадут все подходящие под маску файлы, независимо от глубины их залегания. При такой обработке обязательно используйте свойство ПолноеИмя, так как имена файлов в разных папках могут совпадать, и только полный путь гарантирует уникальность объекта при передаче на сервер.