Перейти к основному содержимому

Руководство по API атрибутов файлов NIO2

· 7 мин. чтения

1. Обзор

В этой статье мы собираемся изучить одну из расширенных функций API-интерфейсов файловой системы Java 7 NIO.2, а именно API-интерфейсы файловых атрибутов.

Ранее мы рассмотрели API -интерфейсы File и Path , если вы хотите сначала углубиться в эти основополагающие элементы.

Все файлы, необходимые для обработки операций с файловой системой, объединены в пакет java.nio.file :

import java.nio.file.*;

2. Основные атрибуты файла

Начнем с высокоуровневого представления основных атрибутов, общих для всех файловых систем, предоставляемых BasicFileAttributeView , в котором хранятся все обязательные и необязательные видимые атрибуты файлов.

Мы можем изучить основные атрибуты домашнего местоположения пользователя на текущем компьютере, создав путь к HOME и получив представление его основных атрибутов:

String HOME = System.getProperty("user.home");
Path home = Paths.get(HOME);
BasicFileAttributeView basicView =
Files.getFileAttributeView(home, BasicFileAttributeView.class);

После вышеуказанного шага теперь мы можем прочитать все атрибуты пути, на который указывает, в одной массовой операции:

BasicFileAttributes basicAttribs = basicView.readAttributes();

Теперь мы можем изучить различные общие атрибуты, которые мы можем использовать в наших приложениях, особенно в условных операторах.

Мы можем запросить размер файла из его контейнера основных атрибутов:

@Test
public void givenPath_whenGetsFileSize_thenCorrect() {
long size = basicAttribs.size();
assertTrue(size > 0);
}

Мы также можем проверить, является ли это каталогом:

@Test
public void givenPath_whenChecksIfDirectory_thenCorrect() {
boolean isDir = basicAttribs.isDirectory();
assertTrue(isDir);
}

Или обычный файл:

@Test
public void givenPath_whenChecksIfFile_thenCorrect() {
boolean isFile = basicAttribs.isRegularFile();
assertFalse(isFile);
}

С Java NIO.2 мы теперь можем иметь дело с символическими ссылками или программными ссылками в файловой системе. Это файлы или каталоги, которые мы обычно называем ярлыками.

Чтобы проверить, является ли файл символической ссылкой:

@Test
public void givenPath_whenChecksIfSymLink_thenCorrect() {
boolean isSymLink = basicAttribs.isSymbolicLink();
assertFalse(isSymLink);
}

В редких случаях мы можем вызвать isOther API, чтобы проверить, не принадлежит ли файл ни к одной из распространенных категорий обычных файлов, каталогов или символических ссылок:

@Test
public void givenPath_whenChecksIfOther_thenCorrect() {
boolean isOther = basicAttribs.isOther();
assertFalse(isOther);
}

Чтобы получить время создания файла:

FileTime created = basicAttribs.creationTime();

Чтобы получить время последнего изменения:

FileTime modified = basicAttribs.lastModifiedTime();

И чтобы получить последнее время доступа:

FileTime accessed = basicAttribs.lastAccessTime();

Все приведенные выше примеры возвращают объект FileTime . Это более удобная абстракция, чем простая отметка времени.

Например, мы можем легко сравнить время двух файлов, чтобы узнать, какое событие произошло до или после другого:

@Test
public void givenFileTimes_whenComparesThem_ThenCorrect() {
FileTime created = basicAttribs.creationTime();
FileTime modified = basicAttribs.lastModifiedTime();
FileTime accessed = basicAttribs.lastAccessTime();

assertTrue(0 >= created.compareTo(accessed));
assertTrue(0 <= modified.compareTo(created));
assertTrue(0 == created.compareTo(created));
}

API compareTo работает так же, как и другие сопоставимые объекты в Java. Он возвращает отрицательное значение, если объект, для которого он вызывается, меньше аргумента; в нашем случае время создания определенно предшествует времени доступа, как в первом утверждении.

Во втором утверждении мы получаем положительное целочисленное значение, потому что модификация может быть сделана только после события создания. И, наконец, он возвращает 0, когда сравниваемые моменты времени равны.

Когда у нас есть объект FileTime, мы можем преобразовать его в большинство других единиц измерения в зависимости от наших потребностей; дни, часы, минуты, секунды, миллисекунды и так далее. Мы делаем это, вызывая соответствующий API:

accessed.to(TimeUnit.SECONDS);
accessed.to(TimeUnit.HOURS);
accessed.toMillis();

Мы также можем распечатать удобочитаемую форму времени файла, вызвав его toString API:

accessed.toString();

Который печатает что-то полезное в формате времени ISO:

2016-11-24T07:52:53.376Z

Мы также можем изменить атрибуты времени в представлении, вызвав его setTimes(modified, accessed, created) API. Мы передаем новые объекты FileTime , которые мы хотим изменить, или null, где мы не хотим изменяться.

Чтобы изменить время последнего доступа на одну минуту вперед, мы должны выполнить следующие шаги:

FileTime newAccessTime = FileTime.fromMillis(
basicAttribs.lastAccessTime().toMillis() + 60000);
basicView.setTimes(null, newAccessTime , null);

Это изменение сохранится в фактическом файле, как видно из любого другого приложения, работающего на машине и использующего файловую систему.

3. Атрибуты файлового пространства

Когда вы открываете мой компьютер в Windows, Linux или Mac, вы обычно можете увидеть графический анализ информации о пространстве на ваших накопителях.

Java NIO.2 делает такую высокоуровневую функциональность очень простой. Он взаимодействует с базовой файловой системой для получения этой информации, в то время как нам нужно вызывать только простые API.

Мы можем использовать класс FileStore для проверки накопителей и получения важной информации, такой как их размер, сколько места используется и сколько еще не используется.

Чтобы получить экземпляр FileStore для расположения произвольного файла в файловой системе, мы используем getFileStore API класса Files :

Path file = Paths.get("file");
FileStore store = Files.getFileStore(file);

Этот экземпляр FileStore конкретно представляет хранилище файлов, в котором находится указанный файл, а не сам файл. Чтобы получить общее пространство:

long total = store.getTotalSpace();

Чтобы получить использованное пространство:

long used = store.getTotalSpace() - store.getUnallocatedSpace();

Мы с меньшей вероятностью будем следовать этому подходу, чем следующему.

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

Iterable<FileStore> fileStores = FileSystems.getDefault().getFileStores();

Затем мы можем перебрать возвращенные значения в цикле и сделать с информацией все, что нам нужно, например, обновить графический интерфейс пользователя:

for (FileStore fileStore : fileStores) {
long totalSpace = fileStore.getTotalSpace();
long unAllocated = fileStore.getUnallocatedSpace();
long usable = fileStore.getUsableSpace();
}

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

Разница между нераспределенным пространством и используемым пространством заключается в доступности для JVM.

Полезное пространство — это пространство, доступное для JVM, в то время как нераспределенное пространство — это доступное пространство, которое видит базовая файловая система. Поэтому полезное пространство иногда может быть меньше нераспределенного пространства.

4. Атрибуты владельца файла

Чтобы проверить информацию о владении файлом, мы используем интерфейс FileOwnerAttributeView . Это дает нам высокоуровневое представление информации о владении.

Мы можем создать объект FileOwnerAttributeView следующим образом:

Path path = Paths.get(HOME);
FileOwnerAttributeView ownerView = Files.getFileAttributeView(
attribPath, FileOwnerAttributeView.class);

Чтобы получить владельца файла из приведенного выше представления:

UserPrincipal owner = ownerView.getOwner();

На самом деле мы ничего не можем сделать программно с вышеуказанным объектом, кроме как получить имя владельца для какой-то другой произвольной цели:

String ownerName = owner.toString();

5. Определяемые пользователем атрибуты файла

Существуют сценарии, в которых атрибуты файла, определенные в файловой системе, недостаточны для ваших нужд. Если вы столкнулись с таким случаем и вам нужно установить свои собственные атрибуты для файла, вам пригодится интерфейс UserDefinedFileAttributeView :

Path path = Paths.get("somefile");
UserDefinedFileAttributeView userDefView = Files.getFileAttributeView(
attribPath, UserDefinedFileAttributeView.class);

Чтобы получить список пользовательских атрибутов, уже определенных для файла, представленного в приведенном выше представлении:

List<String> attribList = userDefView.list();

Чтобы установить пользовательский атрибут в файле, мы используем следующую идиому:

String name = "attrName";
String value = "attrValue";
userDefView.write(name, Charset.defaultCharset().encode(value));

Когда вам нужно получить доступ к определенным пользователем атрибутам, вы можете перебрать список атрибутов, возвращаемый представлением, и проверить их, используя эту идиому:

ByteBuffer attrValue = ByteBuffer.allocate(userView.size(attrName));
userDefView.read(attribName, attribValue);
attrValue.flip();
String attrValue = Charset.defaultCharset().decode(attrValue).toString();

Чтобы удалить определенный пользователем атрибут из файла, мы просто вызываем API удаления представления:

userDefView.delete(attrName);

6. Заключение

В этой статье мы рассмотрели некоторые из менее часто используемых функций, доступных в API-интерфейсах файловой системы Java 7 NIO.2, в частности API-интерфейсы файловых атрибутов.

Полный исходный код примеров, использованных в этой статье, доступен в проекте Github .