API de chemin d’accès Java NIO2

API Java NIO2 Path

1. Vue d'ensemble

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

Les APIPath 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. Installer

La prise en charge de NIO2 est incluse dans le packagejava.nio.file. Donc, configurer votre projet pour utiliser les APIPath est juste une question d'importer tout ce qui se trouve dans ce package:

import java.nio.file.*;

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

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

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

La classePaths est le point d'entrée principal de toutes les opérations impliquant des chemins de système de fichiers. Cela nous permet de créer et de manipuler des chemins d'accès aux fichiers et aux répertoires.

Il convient de noter que les opérations sur les chemins sont principalement de nature syntaxique; ils n'ont aucun effet sur le système de fichiers sous-jacent, pas plus que le système de fichiers n'a d'effet sur leur succès ou leur échec. Cela signifie que le fait de transmettre 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 ce dernier.

3. Opérations de chemin

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

Un objetPath 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 objetsPath. Il a deux méthodes statiques pour créer unPath à partir d'une chaîne de chemin:

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

Que nous utilisions une barre oblique directe ou inverse dans le cheminString, n'a pas d'importance, l'API résout ce paramètre en fonction des exigences du système de fichiers sous-jacent.

Et à partir d'un objetjava.net.URI:

Path path = Paths.get(URI object);

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

4. Créer un chemin

À l'objetcreate a Path à partir d'une chaîne de chemin:

@Test
public void givenPathString_whenCreatesPathObject_thenCorrect() {
    Path p = Paths.get("/articles/example");

    assertEquals("\\articles\\example", p.toString());
}

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

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

@Test
public void givenPathParts_whenCreatesPathObject_thenCorrect() {
    Path p = Paths.get("/articles", "example");

    assertEquals("\\articles\\example", p.toString());
}

5. Récupération des informations de chemin

Vous pouvez considérer l'objet Path comme des éléments de nom comme une séquence. Un cheminString tel queE:\examplerticles\java se compose de trois éléments de nom, c'est-à-dire example,articles etjava. L'élément le plus élevé de la structure du répertoire se trouverait à l'index 0, dans ce cas étantexample.

L'élément le plus bas de la structure du répertoire serait situé à 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é lesfile name, qu'il s'agisse d'un fichier réel ou non:

@Test
public void givenPath_whenRetrievesFileName_thenCorrect() {
    Path p = Paths.get("/articles/example/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/example/logs");
    Path name0 = getName(0);
    Path name1 = getName(1);
    Path name2 = getName(2);
    assertEquals("articles", name0.toString());
    assertEquals("example", 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/example/logs");

    Path subPath1 = p.subpath(0,1);
    Path subPath2 = p.subpath(0,2);

    assertEquals("articles", subPath1.toString());
    assertEquals("articles\\example", subPath2.toString());
    assertEquals("articles\\example\\logs", p.subpath(0, 3).toString());
    assertEquals("example", p.subpath(1, 2).toString());
    assertEquals("example\\logs", p.subpath(1, 3).toString());
    assertEquals("logs", p.subpath(2, 3).toString());
}

Chaque chemin est associé à un chemin parent ou ànull 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. Par 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/example/logs");
    Path p2 = Paths.get("/articles/example");
    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\\example", parent1.toString());
    assertEquals("\\articles", parent2.toString());
    assertEquals("\\", parent3.toString());
    assertEquals(null, parent4);
}

Nous pouvons aussi obtenir l’élément racine d’un chemin:

@Test
public void givenPath_whenRetrievesRoot_thenCorrect() {
    Path p1 = Paths.get("/articles/example/logs");
    Path p2 = Paths.get("c:/articles/example/logs");

    Path root1 = p1.getRoot();
    Path root2 = p2.getRoot();

    assertEquals("\\", root1.toString());
    assertEquals("c:\\", root2.toString());
}

6. Normaliser un chemin

De nombreux systèmes de fichiers utilisent la 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 de répertoire redondantes.

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

/example/./articles
/example/authors/../articles
/example/articles

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

Normaliser un chemin implique de supprimer les redondances. L'opérationPath.normalize() est prévue à cet effet.

Cet exemple devrait maintenant être explicite:

@Test
public void givenPath_whenRemovesRedundancies_thenCorrect1() {
    Path p = Paths.get("/home/./example/articles");

    Path cleanPath = p.normalize();

    assertEquals("\\home\\example\\articles", cleanPath.toString());
}

Celui-là aussi:

@Test
public void givenPath_whenRemovesRedundancies_thenCorrect2() {
    Path p = Paths.get("/home/example/../articles");

    Path cleanPath = p.normalize();

    assertEquals("\\home\\articles", cleanPath.toString());
}

7. Conversion de chemin

Il existe des opérations pour convertir un chemin en 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éthodetoUri:

@Test
public void givenPath_whenConvertsToBrowseablePath_thenCorrect() {
    Path p = Paths.get("/home/example/articles.html");

    URI uri = p.toUri();
    assertEquals(
      "file:///E:/home/example/articles.html",
        uri.toString());
}

Nous pouvons également convertir un chemin en sa représentation absolue. La méthodetoAbsolutePath 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/example/articles.html");

    Path absPath = p.toAbsolutePath();

    assertEquals(
      "E:\\home\\example\\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\\example\\articles.html");

    Path absPath = p.toAbsolutePath();

    assertEquals(
      "E:\\home\\example\\articles.html",
        absPath.toString());
}

Nous pouvons également convertir n'importe quel chemin en son équivalent réel en appelant la méthodetoRealPath. Cette méthode tente de résoudre le chemin en mappant ses éléments aux répertoires et fichiers réels du système de fichiers.

Il est temps d'utiliser la variable que nous avons créée dans la sectionSetup qui pointe vers l'emplacement du domicile de l'utilisateur connecté dans le système de fichiers:

@Test
public void givenExistingPath_whenGetsRealPathToFile_thenCorrect() {
    Path p = Paths.get(HOME);

    Path realPath = p.toRealPath();

    assertEquals(HOME, realPath.toString());
}

Le test ci-dessus ne nous en dit pas beaucoup sur le comportement de cette opération. Le résultat le plus évident est que si le chemin n'existe pas dans le système de fichiers, alors l'opération lancera unIOException, lisez la suite.

En l'absence d'un meilleur moyen de faire passer ce point à la maison, jetez un coup d'œil au prochain test, qui tente de convertir un chemin inexistant en un chemin réel:

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

    p.toRealPath();
}

Le test réussit lorsque nous attrapons unIOException. La sous-classe réelle deIOException que cette opération génère estNoSuchFileException.

8. Rejoindre les chemins

La jonction de deux chemins peut être réalisée en utilisant la méthoderesolve.

En termes simples, nous pouvons appeler la méthoderesolve sur n'importe quelPath et passer unpartial path comme argument. Ce chemin partiel est ajouté au chemin d'origine:

@Test
public void givenTwoPaths_whenJoinsAndResolves_thenCorrect() {
    Path p = Paths.get("/example/articles");

    Path p2 = p.resolve("java");

    assertEquals("\\example\\articles\\java", p2.toString());
}

Cependant, lorsque la chaîne de chemin transmise à la méthoderesolve n'est pas un cheminpartial path; notamment un chemin absolu, le chemin passé est renvoyé:

@Test
public void givenAbsolutePath_whenResolutionRetainsIt_thenCorrect() {
    Path p = Paths.get("/example/articles");

    Path p2 = p.resolve("C:\\example\\articles\java");

    assertEquals("C:\\example\\articles\\java", p2.toString());
}

La même chose se produit avec n'importe quel chemin comportant un élément racine. La chaîne de chemin“java” n'a pas d'élément racine tandis que la chaîne de chemin“/java” a un élément racine. Par conséquent, lorsque vous passez dans un chemin avec un élément racine, celui-ci est renvoyé tel quel:

@Test
public void givenPathWithRoot_whenResolutionRetainsIt_thenCorrect2() {
    Path p = Paths.get("/example/articles");

    Path p2 = p.resolve("/java");

    assertEquals("\\java", p2.toString());
}

9. CheminsRelativizing

Le termerelativizing signifie simplement créer un chemin direct entre deux chemins connus. Par exemple, si nous avons un répertoire/example et à l'intérieur, nous avons deux autres répertoires tels que/example/authors et/example/articles sont des chemins valides.

Le chemin versarticles par rapport àauthors serait décrit comme“move one level up in the directory hierarchy then into articles directory” ou..rticles:

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

En supposant que nous déplaçons le répertoirearticles vers le dossierauthors afin qu'ils ne soient plus frères et sœurs. Les opérations de relativisation suivantes impliquent la création d'un chemin entreexample etarticles et vice versa:

@Test
public void givenNonSiblingPaths_whenCreatesPathToOther_thenCorrect() {
    Path p1 = Paths.get("/example");
    Path p2 = Paths.get("/example/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. Comparaison des chemins

La classePath a une implémentation intuitive de la méthodeequals qui nous permet de comparer deux chemins pour l'égalité:

@Test
public void givenTwoPaths_whenTestsEquality_thenCorrect() {
    Path p1 = Paths.get("/example/articles");
    Path p2 = Paths.get("/example/articles");
    Path p3 = Paths.get("/example/authors");

    assertTrue(p1.equals(p2));
    assertFalse(p1.equals(p3));
}

Vous pouvez également vérifier si un chemin commence par une chaîne donnée:

@Test
public void givenPath_whenInspectsStart_thenCorrect() {
    Path p1 = Paths.get("/example/articles");

    assertTrue(p1.startsWith("/example"));
}

Ou se termine par une autre chaîne:

@Test
public void givenPath_whenInspectsEnd_thenCorrect() {
    Path p1 = Paths.get("/example/articles");

    assertTrue(p1.endsWith("articles"));
}

11. Conclusion

Dans cet article, nous avons présenté les opérations Path dans la nouvelle API de système de fichiers (NIO2), intégrée à Java 7, et la plupart d’entre elles en action.

Les exemples de code utilisés dans cet article se trouvent dans lesGithub project de l'article.