Массив путей с использованием nio

#java #nio

Вопрос:

Я просто изучаю тему nio и получил следующую задачу: выполнить рекурсивный поиск имени файла с помощью nio. Метод должен возвращать список найденных путей. Когда я запускаю приведенный ниже код на выходе, я вижу только [ ]. Не мог бы кто-нибудь объяснить и поправить меня?

 public class Task01 {
    public static void main(String[] args) throws IOException {
        Path dir = Paths.get("C:\Users\......");
        System.out.println(findFile(dir, "Task01.java"));
    }

    public static ArrayList<Path> findFile(Path path, String filename) throws IOException {
        Path dir = Paths.get("C:\....");
        ArrayList<Path> list1 = new ArrayList<>();

        try (DirectoryStream<Path> stream = Files.newDirectoryStream(path, filename)) {
            for (Path entry : stream) {
                if (path.toFile().isDirectory()) {
                    findFile(path, filename);
                } else list1.add(entry.toAbsolutePath());
            }

        }
        return list1;
    }
}

 

Комментарии:

1. В своих if..else заявлениях используйте entry вместо path

Ответ №1:

Этот код может сработать для вас:

 public static ArrayList<Path> findFile(Path path, String filename) throws IOException {
    ArrayList<Path> list1 = new ArrayList<>();

    try (DirectoryStream<Path> stream = Files.newDirectoryStream(path,filename)) {
        for (Path entry : stream) {
            System.out.println(entry  "-" entry.getFileName());
            if (Files.isDirectory(entry)) {
                list1.addAll(findFile(entry, filename));
            } 
            else if (entry.getFileName().toString().equals(filename)) 
                list1.add(entry.toAbsolutePath());
        }

    }
    return list1;
}
 
  • При передаче имени файла в Files.newDirectoryStream(путь,имя файла) он будет искать только в самом пути, без подкаталогов. Таким образом, вы не можете передавать имя файла здесь для фильтрации.
  • если вы вызываете свой метод рекурсивно, вы также должны убедиться, что возвращаемые значения передаются вверх: list1.addAll(findFile(entry, filename));
  • в цикле for всегда работайте с entry , path иначе вы не обрабатываете свою структуру каталогов рекурсивно. (см. Files.isDirectory(entry) вместо path.toFile().isDirectory()

ОБНОВЛЕНИЕ: улучшено использование API java.nio (благодаря @Andreas). Это правильно, что я меньше знаком с nio api.

Комментарии:

1. Проголосовали за, но: Не смешивайте старые и новые API, если это абсолютно необходимо, так что не звоните toFile() ! — Не используй entry.toFile().isDirectory() , используй Files.isDirectory(entry) . — Не используй entry.toFile().getName() , используй entry.getFileName().toString() . А еще лучше, используйте else if (entry.endsWith(filename)) . — — — Кроме того, entry.getName(entry.getNameCount()-1) это очень многословный способ написания entry.getFileName() .

Ответ №2:

Прежде всего, при выполнении рекурсии вы хотите использовать entry вместо path , иначе вы не спуститесь по дереву каталогов.

Также используйте Files.newDirectoryStream(path) вместо Files.newDirectoryStream(path, fileNamePattern) второго метода создание потока в пути, имя файла которого совпадает с именем файла, в вашем случае оно будет пустым [] , если вы Test.java не находитесь в path

 public static void main(String[] args) throws IOException {
    Path dir = Paths.get("E:\dev\...");
    System.out.println(findFile(dir, "TestA.java"));
}

public static ArrayList<Path> findFile(Path path, String filename) throws IOException {
    ArrayList<Path> list1 = new ArrayList<>();

    try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) {
        for (Path entry : stream) {
            if (Files.isDirectory(entry)) {
               list1.addAll(findFile(entry, filename));
            } else if(entry.getFileName().endsWith(filename)){
               list1.add(entry.toAbsolutePath());
            }
        }
    }
    return list1;
}
 

Комментарии:

1. Используйте Files.isDirectory(entry) . — Зачем звонить getName() раньше endsWith() ? В этом нет необходимости. Кроме того, getFileName() это намного короче/по точкам , чем getName(entry.getNameCount()-1) , если вам нужно выполнить эту операцию.

2. @Andreas правильно, я внес изменения в код на основе ваших комментариев

3. Нет, вы этого не сделали, вы перепутали код при попытке применить вторую часть, и вы не выполнили первую часть.