API Java NIO2 Path

1. Vue d'ensemble

Dans cet article, nous allons apprendre à utiliser la nouvelle API de chemin d' E / S (NIO2) en Java.

Les API Path de NIO2 constituent l'un des nouveaux domaines fonctionnels majeurs livrés avec Java 7 et plus précisément un sous-ensemble de la nouvelle API de système de fichiers aux côtés des API de fichiers.

2. Configuration

La prise en charge de NIO2 est fournie dans le package java.nio.file . Donc, configurer votre projet pour utiliser les API Path est juste une question d'importer tout dans ce package:

import java.nio.file.*;

Étant donné que les exemples de code de cet article seront probablement exécutés dans différents environnements, prenons en compte le répertoire personnel de l'utilisateur:

private static String HOME = System.getProperty("user.home");

Cette variable pointera vers un emplacement valide dans n'importe quel environnement.

La classe Paths est le point d'entrée principal de toutes les opérations impliquant des chemins de système de fichiers. Il nous permet de créer et de manipuler des chemins vers des fichiers et des répertoires.

Il convient de noter que les opérations de chemin sont principalement de nature syntaxique; ils n'ont aucun effet sur le système de fichiers sous-jacent et le système de fichiers n'a aucun effet sur leur réussite ou leur échec. Cela signifie que le passage d'un chemin inexistant en tant que paramètre d'une opération de chemin n'a aucune incidence sur la réussite ou l'échec de l'opération.

3. Opérations sur les chemins

Dans cette section, nous présenterons la principale syntaxe utilisée dans les opérations de chemin. Comme son nom l'indique, la classe Path est une représentation programmatique d'un chemin dans le système de fichiers.

Un objet Path contient le nom de fichier et la liste de répertoires utilisés pour construire le chemin et est utilisé pour examiner, localiser et manipuler les fichiers.

La classe d'assistance, java.nio.file.Paths (au pluriel) est la manière formelle de créer des objets Path . Il a deux méthodes statiques pour créer un chemin à partir d'une chaîne de chemin:

Path path = Paths.get("path string");

Que nous utilisions une barre oblique directe ou inverse dans la chaîne de chemin , peu importe, l'API résout ce paramètre en fonction des exigences du système de fichiers sous-jacent.

Et à partir d'un objet java.net.URI :

Path path = Paths.get(URI object);

Nous pouvons maintenant aller de l'avant et les voir en action.

4. Création d'un chemin

Pour créer un objet Path à partir d'une chaîne de chemin:

@Test public void givenPathString_whenCreatesPathObject_thenCorrect() { Path p = Paths.get("/articles/baeldung"); assertEquals("\\articles\\baeldung", p.toString()); }

L' API get peut prendre un paramètre d'arguments variables de parties de chaîne de chemin (dans ce cas, articles et baeldung ) en plus de la première partie (dans ce cas, articles ).

Si nous fournissons ces parties au lieu d'une chaîne de chemin complète, elles seront utilisées pour construire l'objet Path, nous n'avons pas besoin d'inclure les séparateurs de nom (barres obliques) dans la partie des arguments de variable:

@Test public void givenPathParts_whenCreatesPathObject_thenCorrect() { Path p = Paths.get("/articles", "baeldung"); assertEquals("\\articles\\baeldung", p.toString()); }

5. Récupération des informations de chemin

Vous pouvez considérer l'objet Path comme des éléments de nom en tant que séquence. Une chaîne de chemin telle que E: \ baeldung \ articles \ java se compose de trois éléments de nom, à savoir baeldung , articles et java . L'élément le plus élevé de la structure du répertoire se trouverait à l'index 0, dans ce cas étant baeldung .

L'élément le plus bas de la structure de répertoires se trouverait à l'index [n-1] , où n est le nombre d'éléments de nom dans le chemin. Cet élément le plus bas est appelé le nom du fichier, qu'il s'agisse ou non d'un fichier réel:

@Test public void givenPath_whenRetrievesFileName_thenCorrect() { Path p = Paths.get("/articles/baeldung/logs"); Path fileName = p.getFileName(); assertEquals("logs", fileName.toString()); }

Des méthodes sont disponibles pour récupérer des éléments individuels par index:

@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()); }

ou une sous-séquence du chemin utilisant ces plages d'index:

@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()); }

Chaque chemin est associé à un chemin parent ou nul si le chemin n'a pas de parent. Le parent d'un objet chemin se compose du composant racine du chemin, le cas échéant, et de chaque élément du chemin à l'exception du nom de fichier. À titre d'exemple, le chemin parent de / a / b / c est / a / b et celui de / a est nul:

@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); }

Nous pouvons également obtenir l'élément racine d'un chemin:

@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. Normalisation d'un chemin

De nombreux systèmes de fichiers utilisent "." notation pour désigner le répertoire courant et «..» pour désigner le répertoire parent. Vous pouvez avoir une situation où un chemin contient des informations d'annuaire redondantes.

Par exemple, considérez les chaînes de chemin suivantes:

/baeldung/./articles /baeldung/authors/../articles /baeldung/articles

Ils résolvent tous au même endroit / baeldung / articles . Les deux premiers ont des redondances alors que le dernier n'en a pas.

Normaliser un chemin implique de supprimer les redondances qu'il contient. L'opération Path.normalize () est fournie à cet effet.

Cet exemple devrait maintenant être explicite:

@Test public void givenPath_whenRemovesRedundancies_thenCorrect1() { Path p = Paths.get("/home/./baeldung/articles"); Path cleanPath = p.normalize(); assertEquals("\\home\\baeldung\\articles", cleanPath.toString()); }

Celui-là aussi:

@Test public void givenPath_whenRemovesRedundancies_thenCorrect2() { Path p = Paths.get("/home/baeldung/../articles"); Path cleanPath = p.normalize(); assertEquals("\\home\\articles", cleanPath.toString()); }

7. Conversion de chemin

Il existe des opérations pour convertir un chemin dans un format de présentation choisi. Pour convertir n'importe quel chemin en une chaîne qui peut être ouverte à partir du navigateur, nous utilisons la méthode 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()); }

Nous pouvons également convertir un chemin en sa représentation absolue. La méthode toAbsolutePath résout un chemin par rapport au répertoire par défaut d'un système de fichiers:

@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()); }

Cependant, lorsque le chemin à résoudre est détecté comme étant déjà absolu, la méthode le renvoie tel quel:

@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()); }

We can also convert any path to its real equivalent by calling the toRealPath method. This method tries to resolve the path by mapping it's elements to actual directories and files in the file system.

Time to use the variable we created in the Setup section which points to logged-in user's home location in the file system:

@Test public void givenExistingPath_whenGetsRealPathToFile_thenCorrect() { Path p = Paths.get(HOME); Path realPath = p.toRealPath(); assertEquals(HOME, realPath.toString()); }

The above test does not really tell us much about the behavior of this operation. The most obvious result is that if the path does not exist in the file system, then the operation will throw an IOException, read on.

For the lack of a better way to drive this point home, just take a look at the next test, which attempts to convert an inexistent path to a real path:

@Test(expected = NoSuchFileException.class) public void givenInExistentPath_whenFailsToConvert_thenCorrect() { Path p = Paths.get("E:\\home\\baeldung\\articles.html"); p.toRealPath(); }

The test succeeds when we catch an IOException. The actual subclass of IOException that this operation throws is NoSuchFileException.

8. Joining Paths

Joining any two paths can be achieved using the resolve method.

Simply put, we can call the resolve method on any Path and pass in a partial path as the argument. That partial path is appended to the original path:

@Test public void givenTwoPaths_whenJoinsAndResolves_thenCorrect() { Path p = Paths.get("/baeldung/articles"); Path p2 = p.resolve("java"); assertEquals("\\baeldung\\articles\\java", p2.toString()); }

However, when the path string passed to the resolve method is not a partial path; most notably an absolute path, then the passed-in path is returned:

@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()); }

The same thing happens with any path that has a root element. The path string “java” has no root element while the path string “/java” has a root element. Therefore, when you pass in a path with a root element, it is returned as is:

@Test public void givenPathWithRoot_whenResolutionRetainsIt_thenCorrect2() { Path p = Paths.get("/baeldung/articles"); Path p2 = p.resolve("/java"); assertEquals("\\java", p2.toString()); }

9. Relativizing Paths

The term relativizing simply means creating a direct path between two known paths. For instance, if we have a directory /baeldung and inside it, we have two other directories such that /baeldung/authors and /baeldung/articles are valid paths.

The path to articles relative to authors would be described as “move one level up in the directory hierarchy then into articles directory” or ..\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()); }

Assuming we move the articles directory to authors folder such that they are no longer siblings. The following relativizing operations involve creating a path between baeldung and articles and vice versa:

@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. Comparing Paths

The Path class has an intuitive implementation of the equals method which enables us to compare two paths for equality:

@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)); }

You can also check if a path begins with a given string:

@Test public void givenPath_whenInspectsStart_thenCorrect() { Path p1 = Paths.get("/baeldung/articles"); assertTrue(p1.startsWith("/baeldung")); }

Or ends with some other string:

@Test public void givenPath_whenInspectsEnd_thenCorrect() { Path p1 = Paths.get("/baeldung/articles"); assertTrue(p1.endsWith("articles")); }

11. Conclusion

Dans cet article, nous avons montré les opérations Path dans la nouvelle API de système de fichiers (NIO2) qui a été fournie avec Java 7 et avons vu la plupart d'entre elles en action.

Les exemples de code utilisés dans cet article se trouvent dans le projet Github de l'article.