Pull to refresh

Pathосные новшества JDK7. Работа с файловой системой

Данная статья является вольным переводом с авторскими комментариями учебного пособия компании Oracle, по работе с системой ввода-вывода, файлами, папками, реализованной в пакете java.nio.file. Сами разработчики предупреждают, что информация находится в процессе разработки и коррекции ошибок(в ожидании релиза JDK7), и предоставляется нам как ознакомительная, что, в прочем, не мешает нам использовать ее уже сейчас. Чтобы вывести изложение из чисто теоретического ключа, к более практическому, я сфокусирую внимание на тех «вкусностях», что помогут желающим написать, н-р, свой файловый менеджер. Итак, опустив вводную про то, что такое имя файла, структура файловой системы и прочее, приступим.

Класс Path


Прежде чем перейти к более интересному материалу, необходимо рассмотреть базовый класс Path.
Класс Path включает в себя различные методы, которые могут быть использованы для получения информации о пути, получения доступа к элементам пути, преобразования пути в другие формы, извлечения части пути. Существуют также методы для сравнения строк пути и методы для удаления избыточности.

Для создания экземпляра класса Path, воспульзуемся статическим методом get класса Paths, позволяющего создать путь из строки или URI.
Path path1 = Paths.get("/home/iam/folder");<br/>
Path path2 = Paths.get("C:\\this\\my\\folder");<br/>
Path path3 = Paths.get("file:///Users/user/myfile.txt");


После того как экземпляр Path создан, мы можем получить некоторую информацию о пути:

//Path path = Paths.get("C:\\home\\joe\\foo");    // Microsoft Windows syntax<br/>
Path path = Paths.get("/home/iam/folder");       // Solaris syntax<br/>
System.out.format("toString: %s%n", path.toString());              //-->/home/iam/folder<br/>
System.out.format("getName: %s%n", path.getName());           //-->folder<br/>
System.out.format("getName(0): %s%n", path.getName(0));    //-->home<br/>
System.out.format("getNameCount: %d%n", path.getNameCount());  //-->3<br/>
System.out.format("subpath(0,2): %d%n", path.subpath(0,2)); <br/>
System.out.format("getParent: %s%n", path.getParent());        //-->/home/iam/<br/>
System.out.format("getRoot: %s%n", path.getRoot());              //-->/<br/>
System.out.format("isHidden: %s%n", path.isHidden());           //-->false

метод subpath остался без вывода не случайно. Он упорно не хочет работать ни в Win7 ни Ubuntu, о чем я сообщил куда надо. Хотя этот пример взят с оригинального туторала, а в прочем это не единственная ошибочка.

Файлы и атрибуты файлов. Управление метаданными.


Определение «метаданные» можно истолковать как «данные о других данных.» В контексте работы с файловой системой, это могут быть данные, содержащиеся в файлах и каталогах, а также метаданные, представляющие информацию о каждом из этих объектов: является ли объект обычным файлом, директорией, или представляет собой ссылку? Каков его размер, дата создания, дата последнего изменения, кто владелец файла, какая группа владельца, и какие права доступа?
Пакет java.nio.file.attribute предоставляет API для управления метаданными файловой системы, или, как это обычно называется, — атрибутов файлов. Поскольку разные файловые системы имеют разные понятия о том, какие атрибуты должны быть отслежены, наиболее общие атрибуты файла объединяются в так называемые представления. Такое представление отображается с учетом специфики конкретной реализации файловой системы, н-р, POSIX или DOS, или на основе общих функций, таких как информация о владельце файла.
Поддерживаются следующие представления:
  • 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;<br/>
import java.nio.file.Path;<br/>
import java.nio.file.Paths;<br/>
import java.nio.file.attribute.*;<br/>
 <br/>
public class Main {<br/>
 <br/>
    /**<br/>
     * @param args the command line arguments<br/>
     */
<br/>
    public static void main(String[] args) throws IOException{<br/>
        // TODO code application logic here<br/>
        Path file = Paths.get("/home/aum/Downloads/demotivatory_15.jpg");<br/>
        BasicFileAttributes attr = Attributes.readBasicFileAttributes(file);<br/>
 <br/>
if (attr.creationTime() != null) {<br/>
    System.out.println("creationTime: " + attr.creationTime());<br/>
}<br/>
if (attr.lastAccessTime() != null) {<br/>
    System.out.println("lastAccessTime: " + attr.lastAccessTime());<br/>
}<br/>
if (attr.lastModifiedTime() != null) {<br/>
    System.out.println("lastModifiedTime: " + attr.lastModifiedTime());<br/>
}<br/>
 <br/>
System.out.println("isDirectory: " + attr.isDirectory());<br/>
System.out.println("isOther: " + attr.isOther());<br/>
System.out.println("isRegularFile: " + attr.isRegularFile());<br/>
System.out.println("isSymbolicLink: " + attr.isSymbolicLink());<br/>
System.out.println("size: " + attr.size());<br/>
 <br/>
    }<br/>
 <br/>
}

Результат:
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;<br/>
import java.util.EnumSet;<br/>
import java.nio.file.Files;<br/>
import java.nio.file.Paths;<br/>
import java.io.IOException;<br/>
import java.nio.file.FileVisitResult;<br/>
import java.nio.file.Path;<br/>
import java.nio.file.SimpleFileVisitor;<br/>
import java.nio.file.attribute.BasicFileAttributes;<br/>
import static java.nio.file.FileVisitResult.*;<br/>
 <br/>
//Используем класс SimpleFileVisitor, который реализовывает методы интерфейса FileVisitor<br/>
public  class PrintFiles extends SimpleFileVisitor<Path> {<br/>
    //Выводим информацию о обрабатываемом в данный момент файле.<br/>
// метод Files.probeContentType выводит информацию о типе контента<br/>
    @Override<br/>
    public FileVisitResult visitFile(Path file, BasicFileAttributes attr) throws IOException {<br/>
        if (attr.isSymbolicLink()) {<br/>
            System.out.format("Symbolic link: %s ", file);<br/>
        } else if (attr.isRegularFile()) {<br/>
            System.out.format("Regular file: %s Content is %s%n ", file,Files.probeContentType(file));<br/>
 <br/>
        } else {<br/>
            System.out.format("Other: %s ", file);<br/>
        }<br/>
        System.out.println("(" + attr.size() + "bytes)");<br/>
        return CONTINUE;<br/>
    }<br/>
 <br/>
    //Выводим информацию о посещенном каталоге<br/>
    @Override<br/>
/* Перечисление FileVisitResult имеет следующие варианты<br/>
CONTINUE продолжить проход.<br/>
SKIP_SIBLINGS продолжить проход без осмотра дочерних папок.<br/>
SKIP_SUBTREE продолжить без просмотра объектов данной папки.<br/>
TERMINATE заверщить.<br/>
*/
<br/>
    public FileVisitResult postVisitDirectory(Path dir, IOException exc) {<br/>
        System.out.format("Directory: %s%n", dir);<br/>
        return CONTINUE;<br/>
    }<br/>
    //в случае ошибки доступа к файлу выбрасывается исключение IOException<br/>
       @Override<br/>
    public FileVisitResult visitFileFailed(Path file, IOException exc) {<br/>
        System.err.println(exc);<br/>
        return CONTINUE;<br/>
    }<br/>
    public static void main(String[] args) throws IOException{<br/>
        //создаем объект Path<br/>
        Path startingDir = Paths.get("/home/aum/myjobs/");<br/>
        //создаем экземпляр нашего класса, реализующего FileVisit<br/>
        PrintFiles pf = new PrintFiles();<br/>
 //создаем экземпляр EnumSet, необходимый нам как параметр, и указывающий,<br/>
// что программа при  прохождении дерева файлов, следует по ссылкам<br/>
        EnumSet<FileVisitOption> options = EnumSet.of(FileVisitOption.FOLLOW_LINKS);<br/>
       int maxDepth = 2; //максимальное число уровней каталога для просмотра<br/>
       /* Запуск анализа дерева файлов. Используется один из методов класса Files*/<br/>
       Files.walkFileTree(startingDir, options, maxDepth, pf);<br/>
 <br/>
    }<br/>
}

Результат
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


Более полную информацию можно получить здесь
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.