Pull to refresh

Разбор утилиты Files.walkFileTree();

Reading time4 min
Views58K
Не найдя нигде толкового описания на русском, что за зверь Files.walkFileTree(), и со скрипом освоив его, как оказалось впоследствии, несложный функционал, решил поделиться в рамках закрепления материалом с примерами, чего мне так не хватало.

Метод walkFileTree() позволяет обойти дерево файлов и поддиректорий передаваемого ему в качестве параметра элемента Path…

Две сигнатуры метода

Files.walkFileTree(Path start, FileVisitor<? super Path> visitor);
Files.walkFileTree(Path start, Set<FileVisitOption> options, int maxDepth, FileVisitor<? super Path> visitor);

Где
Path start — директория, содержимое которой предстоит обойти,
FileVisitor visitor — инстанс класса, имплементирующего интерфейс FileVisitor, или наследующего от SimpleFileVisitor(). Последний, на мой взгляд, удобнее использовать, когда не требуется переопределять все методы FileVisitor(), о которых речь пойдет чуть ниже(но все зависит от ситуации),
Set<\FileVisitOption> options — набор опций, определяющих поведение при обходе,
maxDepth — глубина прохода поддиректорий.

Сначала про параметры, которые рано или поздно пригодятся

maxDepth — глубина обхода. При = 0 заход в директорию не будет осуществлен, при = MAX_VALUE директория будет изучена до максимальной глубины, соответственно при maxDepth = 3, проход будет осуществляться на 3 поддиректории «вниз».

FileVisitOption — enum множество, определяющее, стоит ли программе при обходе следовать по символьным ссылкам(в этом случае указывается значение FileVisitOption.FOLLOW_LINKS).

FileVisitor — интерфейс, имеющий 4 метода:

1) FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs) throws IOException;
включает в себя набор методов, которые следует выполнить перед посещением текущей поддиректории. Например, через attrs можно получить из такие данные, как:
lastModifiedTime(),
lastAccessTime(),
creationTime(),
isRegularFile() — true, если перед нами файл,
isDirectory() — true, если перед нами директория,
isSymbolicLink() — true, если объект является ссылкой,
isOther() — true, если рассматриваемый объект не является ни файлом, ни директорией, ни ссылкой,
size() — возвращает размер объекта и
fileKey() — возвращает файловый ключ или null;

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

2) FileVisitResult visitFile(T file, BasicFileAttributes attrs) throws IOException;
набор методов, которые следует выполнить во время посещения текущего файла(можно, например, порыться в его содержимом и поискать вхождения искомой строки, или опять же выяснить, дату последнего посещения, изменения файла или сложить при обходе размер всех файлов, чтобы получить размер директории)

Пример

public class MyFileVisitor extends SimpleFileVisitor<Path> {
    String partOfName;
    String partOfContent;

@Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
        boolean containsName = true;
        if(partOfName!=null && !file.getFileName().toString().contains(partOfName))
            containsName = false;

        String content = new String(Files.readAllBytes(file));
        boolean containsContent = true;
        if(partOfContent!=null && !content.contains(partOfContent))
            containsContent = false;

        if(containsName && containsContent)
            foundFiles.add(file);

        return FileVisitResult.CONTINUE;
    }

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

Или еще пример перегрузки метода visitFile

@Override
    public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
        if(path.toString().endsWith(".rar") || path.toString().endsWith(".zip"))
            archived.add(path.toString());
        return FileVisitResult.CONTINUE;
    }

Программа во время обхода дерева при посещении файла, в случае, если он является zip или rar архивом, добавляет его адрес(path) в виде строки к списку архивных файлов;

3) FileVisitResult visitFileFailed(T file, IOException exc) throws IOException;
Данный метод может пригодиться при ошибке доступа к файлу + он «умеет» пробрасывать Exception. Остальному его можно научить через аннотацию Override. Например, посчитать количество файлов, доступ к которым не удалось получить;

Пример

@Override
    public FileVisitResult visitFileFailed(Path path, IOException exc) throws IOException {
        failed.add(path.toString());
        return FileVisitResult.SKIP_SUBTREE;
    }

В случае неудачной попытки доступа к path, данный путь в виде строки добавляется в лист failed ему подобных, и программа продолжает обход, не посещая его поддиректории;

4) FileVisitResult postVisitDirectory(T dir, IOException exc) throws IOException;
все, что необходимо сделать после посещения директории, нужно перечислить в рамках перегрузки данного метода. Например, пройдя директорию, и уничтожив в ней все файлы, этим методом можно уничтожить и ее саму(мы же помним, что Files.delete(Path dir) удаляет директорию только в случае, если она пустая и не содержит файлов).

Пример

@Override
    public FileVisitResult postVisitDirectory(Path path, IOException exc) throws IOException {
        Files.delete(path);
        return FileVisitResult.CONTINUE;
    }

Завершают работу все вышеописанные методы, возвращая «результаты посещения» (FileVisitResult) объекта, которые принадлежат enum множеству и могут принимать следующие значения:

  1. CONTINUE — продолжает обход дерева;
  2. TERMINATE — заканчивает обход дерева;
  3. SKIP_SUBTREE — продолжает обход, без захода в данную директорию;
  4. SKIP_SIBLINGS — исключает из обхода «родственников» данного файла или директории;
Tags:
Hubs:
+6
Comments5

Articles

Change theme settings