Статьи

Создание файлов и каталогов в NIO.2

В настоящее время множество приложений создают файлы или каталоги для самых разных целей. Будь то создание отчета, экспорт части конфигурации или просто сохранение некоторых данных, важно уметь справляться с этими задачами. Создание файлов и каталогов — одна из наиболее часто используемых функций при работе с файловой системой. Эта часть библиотеки подверглась значительной модернизации. Обновления в этой области включают гарантию атомарности определенных операций, создание файлов и каталогов с предустановленными атрибутами файлов, оптимизацию производительности, а также введение иерархии исключений, которая заменила методы boolean возврата из предыдущих версий библиотеки ввода-вывода.

Методы проверки

Прежде чем мы перейдем к какому-либо коду или объяснению, позвольте мне сделать шаг назад и сосредоточиться на чем-то, что будет иметь важное значение не только для этого поста, но и для ряда постов в будущем. Мне важно знать несколько методов, которые обычно называются методами проверки. Методы проверки включают все те методы, которые используются для выполнения различных проверок перед вызовом действительного кода манипулирования файловой системой. Для удобства все они в классе java.nio.file.Files . Использование этих методов поможет вам предотвратить непредвиденное поведение вашего приложения. Поскольку эти методы действительно просты, я пропущу примеры, посвященные им, и вместо этого буду использовать их в следующих примерах.

Методы проверки
Название метода Описание
exists(Path path, LinkOption... options) Проверяет, существует ли файл.
isExecutable(Path path) Проверяет, является ли файл исполняемым.
isHidden(Path path) Сообщает, считается ли файл скрытым.
isReadable(Path path) Проверяет, доступен ли файл для чтения.
isRegularFile(Path path, LinkOption... options) Проверяет, является ли файл обычным файлом с непрозрачным содержимым.
isSameFile(Path path, Path path2) Проверяет, находятся ли два пути в одном и том же файле.
isWritable(Path path) Проверяет, доступен ли файл для записи.
notExists(Path path, LinkOption... options) Проверяет, не существует ли файл, расположенный по этому пути.

Создание нового каталога

Одним из наиболее важных применений класса Files является создание новых каталогов с использованием метода createDirectory . Создание каталога довольно простой и понятный процесс, поэтому объяснять особо нечего. Как обычно, всегда полезно использовать метод проверки, exists классе Files для обеспечения возможности создания каталога с заданным путем, а также для предотвращения исключения FileAlreadyExistsException . Вся ситуация представлена ​​в следующем фрагменте кода:

1
2
3
4
5
6
7
8
9
Path newDirectoryPath = Paths.get("/home/jstas/directory");
 
if (!Files.exists(newDirectoryPath)) {
    try {
        Files.createDirectory(newDirectoryPath);
    } catch (IOException e) {
        System.err.println(e);
    }
}

Пример кода довольно прост — он создает каталог с указанным путем, если никакой другой элемент файловой системы не находится на указанном пути. Если нам нужно создать целую иерархию каталогов, то нам нужно переключиться на метод createDirectories который ведет себя аналогично и создает целую иерархию, определяемую экземпляром пути. Поскольку каталог является типом файла, мы можем устанавливать свои собственные метаданные ( атрибуты файла ). Мы не только можем это сделать, мы даже можем заранее создать определение метаданных и создать каталог с начальными атрибутами файла в элементарной операции, предотвращающей любые несоответствия на этом пути. Как упоминалось в моей предыдущей статье, существует два поддерживаемых стандарта для управления разрешениями файловой системы: POSIX и ACL.

Разрешения файла POSIX

Во-первых, давайте посмотрим, как мы можем управлять разрешениями файловой системы в POSIX-совместимых системах, таких как системы на базе Linux и Mac OS. Благодаря тому, что разрешения для файлов POSIX довольно просты для понимания, создатели библиотек предоставляют нам удобные инструменты, такие как прямой перевод из строкового представления в набор PosixFilePermission или инструмент преобразования для преобразования указанного набора в объект FileAttribute . Это не единственный способ создания объекта FileAttribute как мы увидим в следующей главе.

Возвращаясь к приведенному примеру, давайте рассмотрим следующий код. Используя fromString метод fromString класса PosixFilePermissions мы можем создать набор элементов PosixFilePermission . Теперь необходимо создать экземпляр FileAttribute для передачи в метод createDirectory который создает наш тестовый каталог. Давайте посмотрим на следующий фрагмент кода:

01
02
03
04
05
06
07
08
09
10
11
12
Path newDirectoryPath = Paths.get("/home/jstas/testPosix");
 
if (!Files.exists(newDirectoryPath)) {
    Set<PosixFilePermission> permissions = PosixFilePermissions.fromString("r-xr-----");
    FileAttribute<Set<PosixFilePermission>> fileAttributes = PosixFilePermissions.asFileAttribute(permissions);
 
    try {
        Files.createDirectory(newDirectoryPath, fileAttributes);
    } catch (IOException e) {
        System.err.println(e);
    }
}

Легко проверить, правильно ли были установлены наши разрешения. Вы можете либо прочитать атрибуты файла непосредственно из кода Java, как я представил в статье Атрибуты файла, либо сделать это вручную. Я использовал системный терминал, чтобы проверить их следующим выводом:

1
dr-xr-----.  2 jstas jstas   4096 Jan  5 13:34 testPosix

Права доступа к файлу ACL

Все становится немного сложнее при управлении разрешениями файловой системы в ACL-совместимых системах, таких как Windows (NT, 2000, XP и новее). Списки ACL могут быть довольно сложными и надежными, поэтому здесь нет ярлыков, как с разрешениями для файлов POSIX. Ключевым моментом здесь является использование анонимного определения класса на основе интерфейса FileAttribute . Этот интерфейс определяет только два метода: name возвращает имя атрибута файла, а value возвращает значение этого атрибута. При работе с ACL интересующий нас атрибут называется «acl: acl» . Метод value просто возвращает список созданных записей ACL.

Давайте посмотрим, что скрыто внутри записи ACL и как создать экземпляр AclEntry . Прежде всего, запись ACL состоит из нескольких объектов:

  • Флаги
  • права доступа
  • Тип
    • Компонент типа определяет, предоставляет ли запись доступ или запрещает доступ.
    • Значения: ALARM , ALLOW , AUDIT , DENY
  • принципал
    • Основной компонент, иногда называемый компонентом who, представляет собой UserPrincipal соответствующий идентификатору, который запись предоставляет или запрещает доступ
    • Значения, полученные с помощью UserPrincipalLookupService

Учитывая сложность одной записи ACL, создатели библиотеки NIO.2 увидели очень подходящего кандидата для реализации шаблона компоновщика. Посетите следующую страницу для получения дополнительной информации о шаблонах проектирования и шаблонах сборки . Таким образом, реализация выбирает соответствующие флаги и разрешения, связывает их с пользователем и устанавливает тип записи. Пожалуйста, изучите следующий фрагмент кода, чтобы ознакомиться с разрешениями ACL:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Path newDirectoryPath = Paths.get("c:", "testACL");
 
if (!Files.exists(newDirectoryPath)) {
    FileAttribute<List<AclEntry>> fileAttributes = new FileAttribute<List<AclEntry>>() {
 
        @Override
        public List<AclEntry> value() {
            // lookup user principal
            FileSystem fileSystem = FileSystems.getDefault();
            UserPrincipalLookupService userPrincipalLookupService = fileSystem.getUserPrincipalLookupService();
            UserPrincipal userPrincipal = null;
            try {
                userPrincipal = userPrincipalLookupService.lookupPrincipalByName("JStas");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
 
            // select ACL flags
            Set<AclEntryFlag> flags = EnumSet.of(AclEntryFlag.FILE_INHERIT, AclEntryFlag.DIRECTORY_INHERIT);
 
            // select ACL permission
            Set<AclEntryPermission> permissions = EnumSet.of(AclEntryPermission.READ_DATA, AclEntryPermission.WRITE_DATA, AclEntryPermission.EXECUTE);
 
            // build ACL entry
            Builder builder = AclEntry.newBuilder();
            builder.setFlags(flags);
            builder.setPermissions(permissions);
            builder.setPrincipal(userPrincipal);
            builder.setType(AclEntryType.DENY);
 
            AclEntry entry = builder.build();
            List<AclEntry> aclEntryList = new ArrayList<>();
            aclEntryList.add(entry);
 
            return aclEntryList;
        }
 
        @Override
        public String name() {
            return "acl:acl";
        }
    };
 
    try {
        Files.createDirectory(newDirectoryPath, fileAttributes);
    } catch (IOException e) {
        System.err.println(e);
    }
}

Чтобы проверить успешное создание каталога и его атрибутов файла в Windows 7, выберите вкладку «Безопасность» в свойствах данной папки и нажмите «Дополнительно». Ваша вновь созданная запись должна быть перечислена в представленной таблице с подробным представлением, подобным этому:

Пример записи ACL (Windows 7)

Пример записи ACL (Windows 7)

Создание нового файла

Основная часть любого кода, связанного с файловой системой, обычно включает в себя код, который создает один или несколько файлов. Для создания файла нам нужно снова использовать класс Files и вызвать метод createFile . Точно так же как каталог, файл может быть создан с начальными атрибутами файла, и применяются те же ограничения. Сказав, что я не собираюсь демонстрировать работу с атрибутами файлов, так как она такая же, как в примере каталога. Еще раз, это действительно простой метод, без зацепок, поэтому все представлено в следующем примере:

1
2
3
4
5
6
7
8
9
Path newFilePath = Paths.get("C:", "a.txt");
 
if (!Files.exists(newFilePath)) {
    try {
        Files.createFile(newFilePath);
    } catch (IOException e) {
        System.err.println(e);
    }
}

Пожалуйста, обратите внимание на использование метода проверки exists который предотвращает FileAlreadyExistsException .

Ссылка: Создание файлов и каталогов в NIO.2 от нашего партнера JCG Якуба Стаса в блоге