До выпуска Java 7 в области листинга содержимого каталогов не было особого интереса. Но поскольку в NIO.2 появился новый способ сделать это, возможно, стоит рассмотреть эту область. Одним из больших плюсов NIO.2 является возможность использовать распечатку и фильтрацию сразу в одном вызове метода. Это обеспечивает элегантное решение для большинства задач листинга / фильтрации, связанных с работой с файловой системой.
Список корневых каталогов
Если мы не работаем с относительными путями, нам нужно знать среду, в которой живет наше приложение, чтобы мы могли определять абсолютные пути. Поскольку файловые системы обычно представляют собой иерархические структуры, существует как минимум один корневой каталог. Чтобы правильно обращаться к файлам и каталогам, мы должны иметь возможность перечислить все эти корневые каталоги. Для этого мы обращаемся к самому экземпляру FileSystem
, чтобы использовать его метод getRootDirectories
, который является альтернативой Java 6-конструкции File.listRoots()
.
1
2
3
|
Iterable<Path> it = FileSystems.getDefault().getRootDirectories(); System.out.println( "Root file system locations: " + Sets.newHashSet(it)); |
* Обратите внимание, что класс Sets
не является частью JDK, а поставляется из библиотеки Guava Google. Я использовал его здесь, просто для удобства, чтобы получить красиво отформатированное строковое представление корневых каталогов.
Со следующим выводом:
1
|
Root file system locations: C:\, D:\, E:\, F:\, G:\, H:\, I:\, |
Распечатка и фильтрация содержимого каталога
Стандартной задачей при работе с файловой системой является просмотр или фильтрация файлов в данном каталоге. Нам может понадобиться изменить, проанализировать или просто перечислить их — по какой-то причине у класса java.nio.file.Files
есть свои спины. Он предлагает три варианта метода newDirectoryStream
которые возвращают объект типа DirectoryStream<Path>
чтобы позволить нам перебирать записи в каталоге. Здесь мы видим явное различие между текущей и предыдущими версиями библиотеки ввода-вывода (возвращая простые массивы), предотвращая NullPointerException
. Следующий пример показывает, как просто перечислить содержимое данного каталога:
01
02
03
04
05
06
07
08
09
10
11
|
Path directoryPath = Paths.get( "C:" , "Program Files/Java/jdk1.7.0_40/src/java/nio/file" ); if (Files.isDirectory(directoryPath)) { try (DirectoryStream<Path> stream = Files.newDirectoryStream(directoryPath)) { for (Path path : stream) { System.out.println(path); } } catch (IOException e) { throw new RuntimeException(e); } } |
Обратите внимание на использование метода проверки isDirectory
который предотвращает NotDirectoryException
. Также обратите внимание на использование конструкции try-with-resources
— DirectoryStream
является одновременно AutoCloseable
и Closeable
(что означает, что его необходимо закрыть в какое-то время), так что try-with-resources
пригодится. Код возвращает следующий вывод:
01
02
03
04
05
06
07
08
09
10
11
|
... C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \CopyOption.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \DirectoryIteratorException.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \DirectoryNotEmptyException.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \DirectoryStream.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \FileAlreadyExistsException.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \Files.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \FileStore.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \FileSystem.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \FileSystemAlreadyExistsException.java ... |
Чтобы обеспечить универсальное использование DirectoryStream<Path>
мы можем фильтровать, используя два основных механизма:
-
newDirectoryStream(Path dir, String glob)
- Фильтрация с использованием
GLOB
- Фильтрация с использованием
-
newDirectoryStream (Path dir, DirectoryStream.Filterfilter)
- Фильтрация с использованием
DirectoryStream.Filter
- Фильтрация с использованием
Фильтрация по шаблону GLOB
Прежде всего нам нужно знать, что такое ГЛОБ. Шаблоны GLOB — это строковые выражения, которые следуют определенным правилам синтаксиса и используются для сопоставления. Пожалуйста, обратитесь к следующей статье для получения дополнительной информации о GLOB и синтаксисе GLOB . Когда дело доходит до фильтрации с помощью GLOB, класс Files
предоставляет нам простой способ сделать это. Давайте посмотрим на следующий пример.
01
02
03
04
05
06
07
08
09
10
11
|
Path directoryPath = Paths.get( "C:" , "Program Files/Java/jdk1.7.0_40/src/java/nio/file" ); if (Files.isDirectory(directoryPath)) { try (DirectoryStream<Path> stream = Files.newDirectoryStream(directoryPath, "File*Exception*" )) { for (Path path : stream) { System.out.println(path); } } catch (IOException e) { throw new RuntimeException(e); } } |
Со следующим выводом:
1
2
3
4
5
|
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \FileAlreadyExistsException.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \FileSystemAlreadyExistsException.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \FileSystemException.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \FileSystemLoopException.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \FileSystemNotFoundException.java |
Фильтрация с помощью DirectoryStream.Filter
Когда для выполняемой задачи требуются более сложные параметры фильтрации, а не просто сопоставление имен файлов, нам необходимо реализовать интерфейс DirectoryStream.Filter<Path>
. Это самый мощный вариант фильтрации, доступный в нашем распоряжении, так как у нас есть доступ к остальной части приложения и мы можем использовать сторонние библиотеки. В следующем примере показана такая ситуация с двумя условиями фильтрации:
- Размер файла должен быть четным числом
- Время выполнения в миллисекундах должно быть четным числом
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
Path directoryPath = Paths.get( "C:" , "Program Files/Java/jdk1.7.0_40/src/java/nio/file" ); DirectoryStream.Filter<Path> filter = new Filter<Path>() { @Override public boolean accept(Path entry) throws IOException { long size = Files.readAttributes(entry, BasicFileAttributes. class , LinkOption.NOFOLLOW_LINKS).size(); long milis = new Date().getTime(); boolean isSizeEvenNumber = size % 2 == 0 ; boolean isTheTimeRight = milis % 2 == 0 ; return isTheTimeRight && isSizeEvenNumber; } }; if (Files.isDirectory(directoryPath)) { try (DirectoryStream<Path> stream = Files.newDirectoryStream(directoryPath, filter)) { for (Path path : stream) { System.out.println(path); } } catch (IOException e) { throw new RuntimeException(e); } } |
Со следующим выводом:
1
2
3
4
5
6
7
8
|
C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \DirectoryStream.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \FileAlreadyExistsException.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \Files.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \NotDirectoryException.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \NotLinkException.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \package-info.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \WatchEvent.java C:\Program Files\Java\jdk1.7.0_40\src\java\nio\ file \WatchService.java |
* Обратите внимание, что в зависимости от используемых условий отфильтрованные файлы могут различаться в зависимости от исполнения.
Ссылка: | Перечисление и фильтрация содержимого каталога в NIO.2 от нашего партнера JCG Якуба Стаса в блоге |