Рубрики
Без рубрики

Руководство По Файлообменнику NIO2

Краткое и практическое руководство по просмотру файлов Java NIO2

Автор оригинала: baeldung.

1. Обзор

В этой статье мы рассмотрим интересную особенность NIO2 – интерфейс FileVisitor .

Все операционные системы и несколько сторонних приложений имеют функцию поиска файлов, в которой пользователь определяет критерии поиска.

Этот интерфейс-то, что нам нужно для реализации такой функциональности в Java-приложении. Если вам нужно выполнить поиск всех файлов .mp3 , найти и удалить файлы .class или найти все файлы, к которым не был получен доступ за последний месяц, то этот интерфейс-то, что вам нужно.

Все классы, необходимые для реализации этой функции, собраны в один пакет:

import java.nio.file.*;

2. Как работает FileVisitor

С помощью интерфейса FileVisitor вы можете перемещаться по дереву файлов на любую глубину и выполнять любые действия с файлами или каталогами, найденными в любой ветви.

Типичная реализация интерфейса FileVisitor выглядит следующим образом:

public class FileVisitorImpl implements FileVisitor {

    @Override
    public FileVisitResult preVisitDirectory(
      Path dir, BasicFileAttributes attrs) {
        return null;
    }

    @Override
    public FileVisitResult visitFile(
      Path file, BasicFileAttributes attrs) {
        return null;
    }

    @Override
    public FileVisitResult visitFileFailed(
      Path file, IOException exc) {       
        return null;
    }

    @Override
    public FileVisitResult postVisitDirectory(
      Path dir, IOException exc) {    
        return null;
    }
}

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

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

FileVisitResult – это перечисление четырех возможных возвращаемых значений для методов интерфейса FileVisitor :

  • FileVisitResult.ПРОДОЛЖИТЬ – указывает, что обход дерева файлов должен продолжаться после завершения метода, возвращающего его
  • FileVisitResult.ЗАВЕРШИТЬ – останавливает обход дерева файлов, и никакие другие каталоги или файлы не посещаются
  • FileVisitResult.SKIP_SUBTREE – этот результат имеет значение только при возврате из каталога previsit API, в другом месте, он работает как ПРОДОЛЖИТЬ . Это указывает на то, что текущий каталог и все его подкаталоги следует пропустить
  • FileVisitResult.SKIP_SIBLINGS – указывает, что обход должен продолжаться без посещения братьев и сестер текущего файла или каталога. Если вызывается на этапе preVisitDirectory , то даже текущий каталог пропускается и postVisitDirectory не вызывается

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

Нам просто нужно вызвать статический walkFileTree API класса Files и передать ему экземпляр класса Path , который представляет начальную точку обхода, а затем экземпляр нашего FileVisitor :

Path startingDir = Paths.get("pathToDir");
FileVisitorImpl visitor = new FileVisitorImpl();
Files.walkFileTree(startingDir, visitor);

3. Пример Поиска Файлов

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

Когда мы находим файл, мы выводим на экран сообщение об успешном выполнении, а когда выполняется поиск по всему файловому дереву без поиска файла, мы также печатаем соответствующее сообщение об ошибке.

3.1. Основной Класс

Мы будем называть этот класс FileSearchExample.java :

public class FileSearchExample implements FileVisitor {
    private String fileName;
    private Path startDir;

    // standard constructors
}

Нам еще предстоит реализовать методы интерфейса. Обратите внимание, что мы создали конструктор, который принимает имя файла для поиска и путь для начала поиска. Мы будем использовать начальный путь только в качестве базового варианта, чтобы сделать вывод о том, что файл не найден.

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

3.2. API-интерфейс preVisitDirectory

Давайте начнем с реализации preVisitDirectory API:

@Override
public FileVisitResult preVisitDirectory(
  Path dir, BasicFileAttributes attrs) {
    return CONTINUE;
}

Как мы уже говорили ранее, этот API вызывается каждый раз, когда процесс обнаруживает новый каталог в дереве. Его возвращаемое значение определяет, что произойдет дальше, в зависимости от того, что мы решим. Именно в этот момент мы бы пропустили определенные каталоги и исключили их из пространства примеров поиска.

Давайте решим не выделять какие-либо каталоги и просто искать во всех из них.

3.3. Файловый файл посещения

Далее мы реализуем Файл посещения API. Именно здесь происходит основное действие. Этот API вызывается каждый раз при обнаружении файла. Мы пользуемся этим, чтобы проверить атрибуты файла, сравнить их с нашими критериями и получить соответствующий результат:

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
    String fileName = file.getFileName().toString();
    if (FILE_NAME.equals(fileName)) {
        System.out.println("File found: " + file.toString());
        return TERMINATE;
    }
    return CONTINUE;
}

В нашем случае мы проверяем только имя посещаемого файла, чтобы узнать, тот ли это файл, который ищет пользователь. Если имена совпадают, мы печатаем сообщение об успешном выполнении и завершаем процесс.

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

3.4. API visitFileFailed

Далее мы реализуем API visitFileFailed . Этот API вызывается, когда определенный файл недоступен для JVM. Возможно, он был заблокирован другим приложением или это может быть просто проблема с разрешениями:

@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
    System.out.println("Failed to access file: " + file.toString());
    return CONTINUE;
}

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

3.5. API postVisitDirectory

Наконец, мы реализуем postVisitDirectory API. Этот API вызывается каждый раз, когда каталог полностью пройден:

@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc){
    boolean finishedSearch = Files.isSameFile(dir, START_DIR);
    if (finishedSearch) {
        System.out.println("File:" + FILE_NAME + " not found");
        return TERMINATE;
    }
    return CONTINUE;
}

Мы используем API Files.isSameFile , чтобы проверить, является ли только что пройденный каталог каталогом, из которого мы начали обход. Если возвращаемое значение true , это означает, что поиск завершен и файл не найден. Поэтому мы завершаем процесс сообщением об ошибке.

Однако, если возвращаемое значение false , это означает, что мы только что закончили обход подкаталога и все еще существует вероятность найти файл в каком-либо другом подкаталоге. Итак, мы продолжаем обход.

Теперь мы можем добавить наш основной метод для выполнения Примера поиска файлов приложения:

public static void main(String[] args) {
    Path startingDir = Paths.get("C:/Users/user/Desktop");
    String fileToSearch = "hibernate-guide.txt"
    FileSearchExample crawler = new FileSearchExample(
      fileToSearch, startingDir);
    Files.walkFileTree(startingDir, crawler);
}

Вы можете поиграть с этим примером, изменив значения начальный каталог и файл для поиска переменных. Когда fileToSearch существует в startingDir или любом из его подкаталогов, вы получите сообщение об успехе, в противном случае-сообщение об ошибке.

4. Заключение

В этой статье мы рассмотрели некоторые из менее часто используемых функций, доступных в API файловой системы Java 7 NIO.2, в частности интерфейс FileVisitor . Нам также удалось пройти этапы создания приложения для поиска файлов, чтобы продемонстрировать его функциональность.

Полный исходный код примеров, используемых в этой статье, доступен в проекте Github .