При разработке механизмов загрузки данных или обработки изображений часто возникает задача найти в определенном каталоге файлы сразу нескольких типов, например, .jpg и .pdf. Стандартная функция платформы 1С НайтиФайлы имеет одну важную особенность: ее параметр Маска не является фильтром в привычном понимании (как в диалогах выбора файлов) и не поддерживает перечисление расширений через точку с запятой. В данной статье мы подробно разберем, как обойти это ограничение и реализовать эффективный поиск файлов по списку расширений.
Прежде всего, проанализируем, почему конструкция вида "*.jpg;*.pdf" не работает. В языке 1С маска поиска для функции НайтиФайлы строится по правилам операционной системы (или упрощенному POSIX). Она допускает использование подстановочных знаков, таких как * (любое количество символов) и ? (один любой символ), а также классов символов в квадратных скобках. Однако символ | или ; воспринимается системой как часть имени файла, а не как разделитель форматов. Поэтому нам придется использовать обходные пути.
Это самый прозрачный и надежный метод. Если нам заранее известен список расширений, мы можем создать массив этих расширений и вызывать функцию НайтиФайлы в цикле. Рассмотрим этот пример подробнее:
ИмяКаталога = "C:\Documents\FilesToProcess";
ИскатьВПодкаталогах = Истина;
МассивМасок = Новый Массив;
МассивМасок.Добавить("*.jpg");
МассивМасок.Добавить("*.pdf");
МассивМасок.Добавить("*.png");
МассивФайлов = Новый Массив;
Для Каждого Маска Из МассивМасок Цикл
НайденныеФайлы = НайтиФайлы(ИмяКаталога, Маска, ИскатьВПодкаталогах);
// Если используется БСП, можно применить ОбщегоНазначения.ЗаполнитьМассивУникальнымиЗначениями
Для Каждого ТекущийФайл Из НайденныеФайлы Цикл
МассивФайлов.Добавить(ТекущийФайл);
КонецЦикла;
КонецЦикла;
Если МассивФайлов.Количество() > 0 Тогда
Для Каждого ЭлементФайл Из МассивФайлов Цикл
Сообщить("Найден файл: " + ЭлементФайл.Имя);
КонецЦикла;
Иначе
Сообщить("Файлы указанных типов не найдены.");
КонецЕсли;
Важный нюанс: при таком подходе, если маски пересекаются (например, "*.doc" и "*.*"), в итоговый массив могут попасть дубликаты. Чтобы этого избежать, рекомендуем проверять наличие файла в результирующем массиве или использовать соответствие для хранения уникальных путей.
В ситуациях, когда в папке находится относительно небольшое количество файлов, проще один раз обратиться к файловой системе, получить список всех объектов с помощью маски "*.*" (или системной функции ПолучитьМаскуВсеФайлы()), а затем отсеять лишнее программно. Проанализируем реализацию этого метода:
ПутьКПапке = "D:\Data\Upload";
СписокНужныхРасширений = ".JPG, .JPEG, .PDF, .PNG"; // Список в верхнем регистре для сравнения
НайденныеОбъекты = НайтиФайлы(ПутьКПапке, "*.*", Ложь);
МассивРезультат = Новый Массив;
Для Каждого ТекущийОбъект Из НайденныеОбъекты Цикл
// Исключаем каталоги из поиска
Если ТекущийОбъект.ЭтоКаталог() Тогда
Продолжить;
КонецЕсли;
РасширениеФайла = ВРЕГ(ТекущийОбъект.Расширение); // Приводим к верхнему регистру
Если СтрНайти(СписокНужныхРасширений, РасширениеФайла) > 0 Тогда
МассивРезультат.Добавить(ТекущийОбъект);
КонецЕсли;
КонецЦикла;
Этот метод часто оказывается быстрее, если количество масок велико, так как каждое обращение к функции НайтиФайлы инициирует новое сканирование дискового пространства, что может быть медленным на сетевых ресурсах.
Для мобильных приложений и веб-клиентов, а также для предотвращения блокировки интерфейса в тонком клиенте, следует использовать асинхронные методы. Разберем, как это работает на примере НайтиФайлыАсинх. Принцип работы с масками остается прежним, но результат мы получаем через объект Обещание.
&НаКлиенте
АсинхроннаяПроцедура ПоискФайловНаСервере()
КаталогПоиска = "C:\Temp";
МассивРезультатов = Новый Массив;
// Выполняем поиск для первого расширения
РезультатPDF = Ждать НайтиФайлыАсинх(КаталогПоиска, "*.pdf");
Для Каждого Файл Из РезультатPDF Цикл
МассивРезультатов.Добавить(Файл);
КонецЦикла;
// Выполняем поиск для второго расширения
РезультатJPG = Ждать НайтиФайлыАсинх(КаталогПоиска, "*.jpg");
Для Каждого Файл Из РезультатJPG Цикл
МассивРезультатов.Добавить(Файл);
КонецЦикла;
// Дальнейшая обработка массива
КонецПроцедуры
Выясним причину, по которой поиск может не работать при переносе базы на сервер под управлением Linux. В ОС Windows файловая система нечувствительна к регистру (case-insensitive), поэтому маска "*.jpg" найдет и "image.JPG". В Linux маска "*.jpg" не найдет файлы с расширением в верхнем регистре.
Чтобы обеспечить кроссплатформенность, мы можем использовать квадратные скобки в маске:
"*.[jJ][pP][gG]" найдет файлы .jpg в любом регистре.ВРЕГ(), описанную во втором способе.Рассмотрим рекомендации по выбору метода в зависимости от условий:
Файл для ненужных расширений.Истина в рекурсивном поиске помните, что 1С обходит все дерево. Если файлы лежат в конкретных подпапках, лучше сначала составить список этих подпапок, а затем запустить поиск в каждой из них.Таким образом, хотя прямого способа указать "список масок" в одной функции не существует, комбинация штатных средств платформы и логических условий позволяет эффективно решать задачи любой сложности по поиску и обработке файлов.