#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. Нет, вы этого не сделали, вы перепутали код при попытке применить вторую часть, и вы не выполнили первую часть.