Эта статья завершает цикл, посвящённый созданию библиотеки поиска файлов. На данный момент мы можем найти нужные файлы, и отсортировать их.
Теперь добавим возможности управления процессом поиска, получения промежуточных результатов, и напишем простейший поисковик с графическим интерфейсом.
Новые возможности
Итак, начнём. Прежде всего, вспомним, каким образом выполняется поиск в нашей библиотеке. Всё предельно просто. Для того чтобы найти файлы нужно вызвать один из методов find...
класса FileFinder
.
Проблема заключается в том, что продолжительность поиска может быть довольно большой, и, если мы просто вызовем метод find...
, то работа программы будет заблокирована, пока он не возвратит результат. Это не играет роли в учебном примере, но если вашей программой будут пользоваться другие люди, такая ситуация недопустима. Конечно, пользователь услышит жужжание винчестера, но, скорее всего, ему не понравится, что программа внешне выглядит «зависнувшей».
Поэтому, нам нужно, чтобы поиск файлов выполнялся отдельно от основной программы (кода, который отвечает за работу интерфейса). Сделать это не сложно. Любая современная операционная система поддерживает многозадачность, и, естественно, в стандартную библиотеку Java входят классы для создания многопоточных (multithreaded) приложений. К сожалению, описание этих классов выходит далеко за рамки этой статьи, поэтому, если у вас возникнут вопросы, советую почитать: «Threads: Doing Two or More Tasks at Once», «Создание многопоточных приложений в Java» (на русском) или любую другую статью о создании многопоточных приложений.
Теперь поиск не будет блокировать работу программы, но кроме этого, хотелось бы знать о текущем состоянии процесса (например, сколько файлов найдено на данный момент). Для этого, наш класс FileFinder
должен периодически передавать информацию о своем состоянии.
Тут возникает два вопроса: «Кому и как передавать информацию?». Ответы предельно просты: «Тому, кто её запросил. С помощью вызова соответствующих методов». Т.е. класс FileFinder
должен содержать список объектов, которые следят за процессом поиска, и периодически вызывать нужные методы.
Естественно, все эти объекты должны иметь одинаковый тип. Тут очень удобно использовать интерфейсы. Если какой-нибудь класс, например, MainPanel
реализует интерфейс SearchListener
, то мы сможем привести объект типа MainPanel
к типу SearchListener
. Кроме того, MainPanel
будет обязан реализовать все методы, объявленные в SearchListener
.
Как видите, идея довольна простая. Теперь приступим к её реализации. В первую очередь я хочу показать, как будет выглядеть программа, использующая нашу библиотеку (рис.1). Как вы уже догадались, это простейшая программа поиска файлов. В верхнем текстовом поле нужно задать начальную папку поиска (можно использовать кнопку «Обзор»). В нижнем поле можно задать регулярное выражение (о правилах составления регулярных выражений, можно прочитать в статье «Анализ данных с помощью регулярных выражений или быстрый способ проверки введённых данных«). Если выражение задано, то в список результатов будут включены те файлы и папки, которые ему соответствуют. Кнопка «Поиск» запускает процесс поиска.
Рис.1. Программа поиска файлов
Во время поиска текст на кнопке «Поиск» изменяется на «Остановить», а напротив соответствующих надписей отображается информация о работе программы (рис.2).
Рис.2. Информация о текущих результатах
После завершения поиска, или если пользователь нажал на кнопку «Остановить», программа открывает окно с результатами (рис.3).
Рис.3. Результаты поиска