Pathосные новшества JDK7. Работа с файловой системой
Данная статья является вольным переводом с авторскими комментариями учебного пособия компании Oracle, по работе с системой ввода-вывода, файлами, папками, реализованной в пакете java.nio.file. Сами разработчики предупреждают, что информация находится в процессе разработки и коррекции ошибок(в ожидании релиза JDK7), и предоставляется нам как ознакомительная, что, в прочем, не мешает нам использовать ее уже сейчас. Чтобы вывести изложение из чисто теоретического ключа, к более практическому, я сфокусирую внимание на тех «вкусностях», что помогут желающим написать, н-р, свой файловый менеджер. Итак, опустив вводную про то, что такое имя файла, структура файловой системы и прочее, приступим.
Класс Path
Прежде чем перейти к более интересному материалу, необходимо рассмотреть базовый класс Path.
Класс Path включает в себя различные методы, которые могут быть использованы для получения информации о пути, получения доступа к элементам пути, преобразования пути в другие формы, извлечения части пути. Существуют также методы для сравнения строк пути и методы для удаления избыточности.
Для создания экземпляра класса Path, воспульзуемся статическим методом get класса Paths, позволяющего создать путь из строки или URI.
Path path1 = Paths. get ( «/home/iam/folder» ) ;
Path path2 = Paths. get ( «C: \\ this \\ my \\ folder» ) ;
Path path3 = Paths. get ( «file:///Users/user/myfile.txt» ) ;
После того как экземпляр Path создан, мы можем получить некоторую информацию о пути:
//Path path = Paths.get(«C:\\home\\joe\\foo»); // Microsoft Windows syntax
Path path = Paths. get ( «/home/iam/folder» ) ; // Solaris syntax
System . out . format ( «toString: %s%n» , path. toString ( ) ) ; //—>/home/iam/folder
System . out . format ( «getName: %s%n» , path. getName ( ) ) ; //—>folder
System . out . format ( «getName(0): %s%n» , path. getName ( 0 ) ) ; //—>home
System . out . format ( «getNameCount: %d%n» , path. getNameCount ( ) ) ; //—>3
System . out . format ( «subpath(0,2): %d%n» , path. subpath ( 0 , 2 ) ) ;
System . out . format ( «getParent: %s%n» , path. getParent ( ) ) ; //—>/home/iam/
System . out . format ( «getRoot: %s%n» , path. getRoot ( ) ) ; //—>/
System . out . format ( «isHidden: %s%n» , path. isHidden ( ) ) ; //—>false
метод subpath остался без вывода не случайно. Он упорно не хочет работать ни в Win7 ни Ubuntu, о чем я сообщил куда надо. Хотя этот пример взят с оригинального туторала, а в прочем это не единственная ошибочка.
Файлы и атрибуты файлов. Управление метаданными.
- BasicFileAttributeView – базовые атрибуты, поддерживаемые всеми реализациями файловых систем.
- DosFileAttributeView – расширяет базовые атрибуты, добавлением стандартных четырех бит, которые используются системами, поддерживающими атрибуты DOS.
- PosixFileAttributeView – поддержка атрибутов стандарта POSIX. Атрибуты включают в себя владельца файла( file owner), группу(group owner), и уровни прав доступа(access permissions).
- FileOwnerAttributeView – поддерживается всеми системами, реализующими концепцию владельца файла.
- AclFileAttributeView – поддерживает чтение и модификацию списков управления доступом файла( Access Control Lists (ACL)). Поддерживается модель NFSv4 ACL. Любая модель ACL, такая как Windows ACL, имеющая проработанную систему отображения к модели NFSv4, также должна поддерживаться.
- UserDefinedFileAttributeView – реализация поддержки пользовательских метаданных.
import java.io.IOException ;
import java.nio.file.Path ;
import java.nio.file.Paths ;
import java.nio.file.attribute.* ;
public class Main < /** * @param args the command line arguments */ public static void main ( String [ ] args ) throws IOException < // TODO code application logic here Path file = Paths. get ( «/home/aum/Downloads/demotivatory_15.jpg» ) ; BasicFileAttributes attr = Attributes . readBasicFileAttributes ( file ) ; if ( attr. creationTime ( ) != null ) < System . out . println ( «creationTime: » + attr. creationTime ( ) ) ; >
if ( attr. lastAccessTime ( ) != null ) < System . out . println ( «lastAccessTime: » + attr. lastAccessTime ( ) ) ; >
if ( attr. lastModifiedTime ( ) != null ) < System . out . println ( «lastModifiedTime: » + attr. lastModifiedTime ( ) ) ; >
System . out . println ( «isDirectory: » + attr. isDirectory ( ) ) ;
System . out . println ( «isOther: » + attr. isOther ( ) ) ;
System . out . println ( «isRegularFile: » + attr. isRegularFile ( ) ) ;
System . out . println ( «isSymbolicLink: » + attr. isSymbolicLink ( ) ) ;
System . out . println ( «size: » + attr. size ( ) ) ;
>
>
Результат:
run:
lastAccessTime: 2011-02-14T14:16:32Z
lastModifiedTime: 2011-02-04T02:17:27Z
isDirectory: false
isOther: false
isRegularFile: true
isSymbolicLink: false
size: 64613
BUILD SUCCESSFUL (total time: 0 seconds)
На этом вводную предлагаю считать завершенной. За бортом осталось множество методов «синтаксической» работы с Path: удаление избыточности в пути, преобразование к абсолютному пути, сравнение путей, создание путей из объеденения и т.п. Всю необходимую информацию вы можете найти здесь (класс Path) И теперь мы смело можем перейти к более сложному, но и более интересному материалу.
Обход дерева файлов
Получение информации о папках и файлах на диске, довольно типичная задача для прикладных программ. Пакет java.nio.file предлагает нам удобное решение такой задачи, предоставляя интерфейс FileVisitor.
FileVisitor определяет требуемое поведение в ключевых точках прохождения процесса: когда файл посещен, прежде чем получить доступ к каталогу, после получения доступа к каталогу, или в случае отказа. Интерфейс состоит из пяти(! оставлю слово пять из оригинального текста, хотя как не старался нашел только 4! метода ) методов, которые соответствуют этим ситуациях:
- preVisitDirectory – вызывается до входа в папку
- postVisitDirectory – вызывается после «просмотра» всех объектов каталога. В случае возникновения ошибки, вызывается исключение и передается методу
- visitFile – вызывается для получения информации о файле, обрабатываемом в данный момент. В метод передаются атрибуты файла BasicFileAttributes, или мы можем передать определенный набор атрибутов, н-р можем выбрать чтение атрибутов DosFileAttributeView, чтобы определить является ли файл скрытым(«hidden»).
- visitFileFailed – вызывается при невозможности получить доступ к файлу. В этом случае вызывается исключение и передается методу. Обработка этого события может быть различной(вызов исключения, запись в лог или вывод информации на консоль и т.д.
import java.nio.file.FileVisitOption ;
import java.util.EnumSet ;
import java.nio.file.Files ;
import java.nio.file.Paths ;
import java.io.IOException ;
import java.nio.file.FileVisitResult ;
import java.nio.file.Path ;
import java.nio.file.SimpleFileVisitor ;
import java.nio.file.attribute.BasicFileAttributes ;
import static java. nio . file . FileVisitResult . *;
//Используем класс SimpleFileVisitor, который реализовывает методы интерфейса FileVisitor
public class PrintFiles extends SimpleFileVisitor < Path >< //Выводим информацию о обрабатываемом в данный момент файле. // метод Files.probeContentType выводит информацию о типе контента @Override public FileVisitResult visitFile ( Path file, BasicFileAttributes attr ) throws IOException < if ( attr. isSymbolicLink ( ) ) < System . out . format ( «Symbolic link: %s » , file ) ; > else if ( attr. isRegularFile ( ) ) < System . out . format ( «Regular file: %s Content is %s%n » , file,Files. probeContentType ( file ) ) ; > else < System . out . format ( «Other: %s » , file ) ; >
System . out . println ( «(» + attr. size ( ) + «bytes)» ) ;
return CONTINUE ;
>
//Выводим информацию о посещенном каталоге
@Override
/* Перечисление FileVisitResult имеет следующие варианты
CONTINUE продолжить проход.
SKIP_SIBLINGS продолжить проход без осмотра дочерних папок.
SKIP_SUBTREE продолжить без просмотра объектов данной папки.
TERMINATE заверщить.
*/
public FileVisitResult postVisitDirectory ( Path dir, IOException exc ) < System . out . format ( «Directory: %s%n» , dir ) ; return CONTINUE ; >
//в случае ошибки доступа к файлу выбрасывается исключение IOException
@Override
public FileVisitResult visitFileFailed ( Path file, IOException exc ) < System . err . println ( exc ) ; return CONTINUE ; >
public static void main ( String [ ] args ) throws IOException < //создаем объект Path Path startingDir = Paths. get ( «/home/aum/myjobs/» ) ; //создаем экземпляр нашего класса, реализующего FileVisit PrintFiles pf = new PrintFiles ( ) ; //создаем экземпляр EnumSet, необходимый нам как параметр, и указывающий, // что программа при прохождении дерева файлов, следует по ссылкам EnumSet < FileVisitOption >options = EnumSet. of ( FileVisitOption. FOLLOW_LINKS ) ;
int maxDepth = 2 ; //максимальное число уровней каталога для просмотра
/* Запуск анализа дерева файлов. Используется один из методов класса Files*/
Files. walkFileTree ( startingDir, options, maxDepth, pf ) ;
>
>
Результат
run:
Regular file: /home/aum/myjobs/sys.txt Content is text/plain
(11362bytes)
Regular file: /home/aum/myjobs/vzriv.mp3 Content is audio/mpeg
(2336827bytes)
Regular file: /home/aum/myjobs/report.html Content is text/html
(24574bytes)
Regular file: /home/aum/myjobs/examples.desktop Content is application/x-desktop
(179bytes)
Directory: /home/aum/myjobs/java
Directory: /home/aum/myjobs
BUILD SUCCESSFUL (total time: 0 seconds)
И в завершении о производительности. Н-р, код указаный выше, выполняется (на моем каталоге /home) так:
Objects found 19931 Total Size 2329851621 byte
BUILD SUCCESSFUL (total time: 38 seconds)
системные характеристики
Ubuntu 10.4
Kernel Linux 2.6.32-28
Gnom 2.30.2
Memory 1.9 G
Intel® Core(TM) i3 CPU M330 @ 2.13 GHz
Более полную информацию можно получить здесь
Java path class import
Path testFile = Paths.get(«C:\\Users\\jleom\\Desktop\\java\\javarush task\\test.txt»); Path testFile2 = Paths.get(«C:\\Users\\jleom\\Desktop»); System.out.println(testFile.relativize(testFile2));
Класс Path и класс Paths предназначены для работы с файловой системой в Java, однако они предоставляют разные функции и методы. Path — это интерфейс, который определяет методы для работы с путями к файлам и каталогам в файловой системе. Он предоставляет ряд методов для работы с путями, таких как resolve(), relativize(), getParent(), getFileName(), toAbsolutePath() и другие. Paths — это утилитный класс, который предоставляет статические методы для создания экземпляров класса Path. Он не имеет методов для работы с путями напрямую, но предоставляет методы для создания экземпляров Path из строковых значений или URI. Еще методы по классу Paths: getFileSystem(): возвращает объект FileSystem, представляющий файловую систему, которой принадлежит данный путь. getDefault(): возвращает объект FileSystem, представляющий файловую систему по умолчанию. getTempDirectory(): возвращает объект типа Path, представляющий временный каталог. getHomeDirectory(): возвращает объект типа Path, представляющий домашний каталог пользователя. exists(Path path, LinkOption. options): проверяет, существует ли файл или каталог, представленный указанным путем. Класс Paths удобен для работы с файловой системой, так как он предоставляет простой и удобный API для работы с путями.
Надо добавить в статью, Paths.get был в 8 Java. Потом появился Path.of. Если у вас не работает Path.of (версия Java не позволяет), только тогда нужен Paths.get