«1. Обзор
В этой статье мы узнаем, как использовать новый I/O (NIO2) Path API в Java.
API-интерфейсы Path в NIO2 представляют собой одну из основных новых функциональных областей, поставляемых с Java 7, и, в частности, подмножество API-интерфейсов новой файловой системы наряду с API-интерфейсами файлов.
2. Настройка
Поддержка NIO2 включена в пакет java.nio.file. Таким образом, настройка вашего проекта для использования Path API — это просто вопрос импорта всего из этого пакета:
import java.nio.file.*;
Так как примеры кода в этой статье, вероятно, будут выполняться в разных средах, давайте разберемся с домашним каталогом. пользователя:
private static String HOME = System.getProperty("user.home");
Эта переменная будет указывать на допустимое местоположение в любой среде.
Класс Paths является основной точкой входа для всех операций с путями в файловой системе. Это позволяет нам создавать и управлять путями к файлам и каталогам.
Следует отметить, что операции с путями в основном носят синтаксический характер; они не влияют на базовую файловую систему, и файловая система также не влияет на их успешность или неудачу. Это означает, что передача несуществующего пути в качестве параметра операции пути не влияет на ее успешность или неудачу.
3. Операции с путями
В этом разделе мы представим основной синтаксис, используемый в операциях с путями. Как следует из названия, класс Path является программным представлением пути в файловой системе.
Объект Path содержит имя файла и список каталогов, используемых для создания пути, и используется для проверки, поиска и управления файлами.
Вспомогательный класс java.nio.file.Paths (во множественном числе) является формальным способом создания объектов Path. У него есть два статических метода для создания пути из строки пути:
Path path = Paths.get("path string");
Независимо от того, используем ли мы прямую или обратную косую черту в строке пути, API разрешает этот параметр в соответствии с требованиями базовой файловой системы.
И из объекта java.net.URI:
Path path = Paths.get(URI object);
Теперь мы можем продолжить и увидеть их в действии.
4. Создание пути
Чтобы создать объект пути из строки пути:
@Test
public void givenPathString_whenCreatesPathObject_thenCorrect() {
Path p = Paths.get("/articles/baeldung");
assertEquals("\\articles\\baeldung", p.toString());
}
API get может принимать переменный аргумент аргументов частей строки пути (в данном случае статьи и баелдунг) дополнение к первой части (в данном случае статьи).
Если мы предоставим эти части вместо полной строки пути, они будут использоваться для создания объекта Path, нам не нужно включать разделители имен (косые черты) в часть переменных аргументов:
@Test
public void givenPathParts_whenCreatesPathObject_thenCorrect() {
Path p = Paths.get("/articles", "baeldung");
assertEquals("\\articles\\baeldung", p.toString());
}
5. Получение информации о пути
Вы можете думать об объекте пути как об элементах имени как о последовательности. Строка пути, такая как E:\\baeldung\\articles\\java, состоит из трех элементов имени, т. е. baeldung, article и java. Самый высокий элемент в структуре каталогов будет располагаться по индексу 0, в данном случае это baeldung.
Самый нижний элемент в структуре каталогов будет располагаться по индексу [n-1], где n — количество элементов имени в пути. Этот самый нижний элемент называется именем файла, независимо от того, является ли он фактическим файлом или нет:
@Test
public void givenPath_whenRetrievesFileName_thenCorrect() {
Path p = Paths.get("/articles/baeldung/logs");
Path fileName = p.getFileName();
assertEquals("logs", fileName.toString());
}
Доступны методы для извлечения отдельных элементов по индексу:
@Test
public void givenPath_whenRetrievesNameByIndex_thenCorrect() {
Path p = Paths.get("/articles/baeldung/logs");
Path name0 = getName(0);
Path name1 = getName(1);
Path name2 = getName(2);
assertEquals("articles", name0.toString());
assertEquals("baeldung", name1.toString());
assertEquals("logs", name2.toString());
}
или части пути с помощью эти диапазоны индексов:
@Test
public void givenPath_whenCanRetrieveSubsequenceByIndex_thenCorrect() {
Path p = Paths.get("/articles/baeldung/logs");
Path subPath1 = p.subpath(0,1);
Path subPath2 = p.subpath(0,2);
assertEquals("articles", subPath1.toString());
assertEquals("articles\\baeldung", subPath2.toString());
assertEquals("articles\\baeldung\\logs", p.subpath(0, 3).toString());
assertEquals("baeldung", p.subpath(1, 2).toString());
assertEquals("baeldung\\logs", p.subpath(1, 3).toString());
assertEquals("logs", p.subpath(2, 3).toString());
}
Каждый путь связан с родительским путем или нулевым, если у пути нет родителя. Родительский объект пути состоит из корневого компонента пути, если он есть, и каждого элемента пути, кроме имени файла. Например, родительский путь /a/b/c равен /a/b, а путь /a равен null:
@Test
public void givenPath_whenRetrievesParent_thenCorrect() {
Path p1 = Paths.get("/articles/baeldung/logs");
Path p2 = Paths.get("/articles/baeldung");
Path p3 = Paths.get("/articles");
Path p4 = Paths.get("/");
Path parent1 = p1.getParent();
Path parent2 = p2.getParent();
Path parent3 = p3.getParent();
Path parent4 = p4.getParenth();
assertEquals("\\articles\\baeldung", parent1.toString());
assertEquals("\\articles", parent2.toString());
assertEquals("\\", parent3.toString());
assertEquals(null, parent4);
}
Мы также можем получить корневой элемент пути:
@Test
public void givenPath_whenRetrievesRoot_thenCorrect() {
Path p1 = Paths.get("/articles/baeldung/logs");
Path p2 = Paths.get("c:/articles/baeldung/logs");
Path root1 = p1.getRoot();
Path root2 = p2.getRoot();
assertEquals("\\", root1.toString());
assertEquals("c:\\", root2.toString());
}
6. Нормализация пути
Многие файловые системы используют нотацию «.» для обозначения текущего каталога и «..» для обозначения родительского каталога. Может возникнуть ситуация, когда путь содержит избыточную информацию о каталоге.
Например, рассмотрим следующие строки пути:
/baeldung/./articles
/baeldung/authors/../articles
/baeldung/articles
Все они разрешаются в одно и то же место /baeldung/articles. Первые два имеют избыточность, а последний — нет.
Нормализация пути включает удаление из него избыточности. Для этой цели предусмотрена операция Path.normalize().
«Этот пример теперь должен быть понятен:
@Test
public void givenPath_whenRemovesRedundancies_thenCorrect1() {
Path p = Paths.get("/home/./baeldung/articles");
Path cleanPath = p.normalize();
assertEquals("\\home\\baeldung\\articles", cleanPath.toString());
}
Этот тоже:
@Test
public void givenPath_whenRemovesRedundancies_thenCorrect2() {
Path p = Paths.get("/home/baeldung/../articles");
Path cleanPath = p.normalize();
assertEquals("\\home\\articles", cleanPath.toString());
}
7. Преобразование пути
Существуют операции для преобразования пути в выбранный формат представления. Чтобы преобразовать любой путь в строку, которую можно открыть из браузера, мы используем метод toUri:
@Test
public void givenPath_whenConvertsToBrowseablePath_thenCorrect() {
Path p = Paths.get("/home/baeldung/articles.html");
URI uri = p.toUri();
assertEquals(
"file:///E:/home/baeldung/articles.html",
uri.toString());
}
Мы также можем преобразовать путь в его абсолютное представление. Метод toAbsolutePath разрешает путь к каталогу файловой системы по умолчанию:
@Test
public void givenPath_whenConvertsToAbsolutePath_thenCorrect() {
Path p = Paths.get("/home/baeldung/articles.html");
Path absPath = p.toAbsolutePath();
assertEquals(
"E:\\home\\baeldung\\articles.html",
absPath.toString());
}
Однако, когда обнаруживается, что путь, который нужно разрешить, уже является абсолютным, метод возвращает его как есть:
@Test
public void givenAbsolutePath_whenRetainsAsAbsolute_thenCorrect() {
Path p = Paths.get("E:\\home\\baeldung\\articles.html");
Path absPath = p.toAbsolutePath();
assertEquals(
"E:\\home\\baeldung\\articles.html",
absPath.toString());
}
Мы также можем преобразовать любой путь в его реальный эквивалент, вызвав метод toRealPath. Этот метод пытается разрешить путь, сопоставляя его элементы с реальными каталогами и файлами в файловой системе.
Время использовать переменную, которую мы создали в разделе «Настройка», которая указывает на домашнюю позицию вошедшего в систему пользователя в файловой системе:
@Test
public void givenExistingPath_whenGetsRealPathToFile_thenCorrect() {
Path p = Paths.get(HOME);
Path realPath = p.toRealPath();
assertEquals(HOME, realPath.toString());
}
Приведенный выше тест на самом деле мало что говорит нам о поведении этой операции. Наиболее очевидным результатом является то, что если путь не существует в файловой системе, то операция выдаст исключение IOException, читайте дальше.
За неимением лучшего способа довести эту точку до ума, просто взгляните на следующий тест, который пытается преобразовать несуществующий путь в реальный путь:
@Test(expected = NoSuchFileException.class)
public void givenInExistentPath_whenFailsToConvert_thenCorrect() {
Path p = Paths.get("E:\\home\\baeldung\\articles.html");
p.toRealPath();
}
Тест завершается успешно, когда мы поймаем IOException. Фактическим подклассом IOException, который выдает эта операция, является NoSuchFileException.
8. Соединение путей
Соединение любых двух путей может быть достигнуто с помощью метода разрешения.
Проще говоря, мы можем вызвать метод разрешения для любого пути и передать частичный путь в качестве аргумента. Этот неполный путь добавляется к исходному пути:
@Test
public void givenTwoPaths_whenJoinsAndResolves_thenCorrect() {
Path p = Paths.get("/baeldung/articles");
Path p2 = p.resolve("java");
assertEquals("\\baeldung\\articles\\java", p2.toString());
}
Однако, когда строка пути, переданная методу разрешения, не является частичным путем; особенно абсолютный путь, затем возвращается переданный путь:
@Test
public void givenAbsolutePath_whenResolutionRetainsIt_thenCorrect() {
Path p = Paths.get("/baeldung/articles");
Path p2 = p.resolve("C:\\baeldung\\articles\java");
assertEquals("C:\\baeldung\\articles\\java", p2.toString());
}
То же самое происходит с любым путем, имеющим корневой элемент. Строка пути «java» не имеет корневого элемента, а строка пути «/java» имеет корневой элемент. Поэтому, когда вы передаете путь с корневым элементом, он возвращается как есть:
@Test
public void givenPathWithRoot_whenResolutionRetainsIt_thenCorrect2() {
Path p = Paths.get("/baeldung/articles");
Path p2 = p.resolve("/java");
assertEquals("\\java", p2.toString());
}
9. Релятивизация путей
Термин релятивизация просто означает создание прямого пути между двумя известными путями. Например, если у нас есть каталог /baeldung и внутри него, у нас есть два других каталога, так что /baeldung/authors и /baeldung/articles являются допустимыми путями.
Путь к статьям относительно авторов будет описан как «переместиться на один уровень вверх в иерархии каталогов, затем в каталог статей» или ..\\articles:
@Test
public void givenSiblingPaths_whenCreatesPathToOther_thenCorrect() {
Path p1 = Paths.get("articles");
Path p2 = Paths.get("authors");
Path p1_rel_p2 = p1.relativize(p2);
Path p2_rel_p1 = p2.relativize(p1);
assertEquals("..\\authors", p1_rel_p2.toString());
assertEquals("..\\articles", p2_rel_p1.toString());
}
Предположим, что мы перемещаем каталог статей в папку авторов чтобы они больше не были братьями и сестрами. Следующие релятивизирующие операции включают создание пути между baeldung и article и наоборот:
@Test
public void givenNonSiblingPaths_whenCreatesPathToOther_thenCorrect() {
Path p1 = Paths.get("/baeldung");
Path p2 = Paths.get("/baeldung/authors/articles");
Path p1_rel_p2 = p1.relativize(p2);
Path p2_rel_p1 = p2.relativize(p1);
assertEquals("authors\\articles", p1_rel_p2.toString());
assertEquals("..\\..", p2_rel_p1.toString());
}
10. Сравнение путей
Класс Path имеет интуитивно понятную реализацию метода equals, который позволяет нам сравнивать два пути на предмет равенства:
@Test
public void givenTwoPaths_whenTestsEquality_thenCorrect() {
Path p1 = Paths.get("/baeldung/articles");
Path p2 = Paths.get("/baeldung/articles");
Path p3 = Paths.get("/baeldung/authors");
assertTrue(p1.equals(p2));
assertFalse(p1.equals(p3));
}
Вы также можете проверить, начинается ли путь с заданной строки:
@Test
public void givenPath_whenInspectsStart_thenCorrect() {
Path p1 = Paths.get("/baeldung/articles");
assertTrue(p1.startsWith("/baeldung"));
}
Или заканчивается какой-либо другой строкой:
@Test
public void givenPath_whenInspectsEnd_thenCorrect() {
Path p1 = Paths.get("/baeldung/articles");
assertTrue(p1.endsWith("articles"));
}
11. Заключение
В этой статье мы показали Операции с путями в новом API файловой системы (NIO2), который был представлен как часть Java 7 и видел большинство из них в действии.
Примеры кода, использованные в этой статье, можно найти в проекте статьи на Github.