Java NIO2 Path API

Java NIO2 Path API

1. Überblick

In diesem Artikel erfahren Sie, wie Sie die neue API für E / A (NIO2)Pathin Java verwenden.

DiePath-APIs in NIO2 bilden einen der wichtigsten neuen Funktionsbereiche, die mit Java 7 ausgeliefert wurden, und insbesondere eine Teilmenge der neuen Dateisystem-API neben den Datei-APIs.

2. Konfiguration

Die NIO2-Unterstützung ist im Paketjava.nio.fileenthalten. Wenn Sie Ihr Projekt für die Verwendung derPath-APIs einrichten, müssen Sie lediglich alles in dieses Paket importieren:

import java.nio.file.*;

Da die Codebeispiele in diesem Artikel wahrscheinlich in verschiedenen Umgebungen ausgeführt werden, erhalten Sie einen Überblick über das Home-Verzeichnis des Benutzers:

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

Diese Variable zeigt auf einen gültigen Ort in einer beliebigen Umgebung.

Die KlassePaths ist der Haupteinstiegspunkt für alle Operationen, die Dateisystempfade betreffen. Es ermöglicht uns, Pfade zu Dateien und Verzeichnissen zu erstellen und zu bearbeiten.

Bemerkenswert ist, dass Pfadoperationen hauptsächlich syntaktischer Natur sind. Sie haben keine Auswirkung auf das zugrunde liegende Dateisystem und das Dateisystem hat auch keine Auswirkung darauf, ob sie erfolgreich sind oder nicht. Dies bedeutet, dass die Übergabe eines nicht vorhandenen Pfads als Parameter einer Pfadoperation keinen Einfluss darauf hat, ob er erfolgreich ist oder fehlschlägt.

3. Pfadoperationen

In diesem Abschnitt werden wir die Hauptsyntax für Pfadoperationen vorstellen. Wie der Name schon sagt, ist die KlassePatheine programmatische Darstellung eines Pfads im Dateisystem.

Das ObjektPathenthält den Dateinamen und die Verzeichnisliste, die zum Erstellen des Pfads verwendet werden, und wird zum Untersuchen, Suchen und Bearbeiten von Dateien verwendet.

Die Hilfsklassejava.nio.file.Paths (im Plural) ist die formale Methode zum Erstellen vonPath-Objekten. Es gibt zwei statische Methoden zum Erstellen einesPath aus einer Pfadzeichenfolge:

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

Es spielt keine Rolle, ob wir im PfadString, einen Vorwärts- oder Rückwärts-Schrägstrich verwenden. Die API löst diesen Parameter gemäß den Anforderungen des zugrunde liegenden Dateisystems auf.

Und von einemjava.net.URI Objekt:

Path path = Paths.get(URI object);

Wir können jetzt weitermachen und diese in Aktion sehen.

4. Einen Pfad erstellen

Zucreate a Path Objekt aus einer Pfadzeichenfolge:

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

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

Dieget-API kann zusätzlich zum ersten Teil (in diesem Fallarticles einen variablen Argumentparameter von Pfadzeichenfolgenteilen (in diesem Fallarticles undexample) verwenden ).

Wenn wir diese Teile anstelle einer vollständigen Pfadzeichenfolge bereitstellen, werden sie zum Erstellen des Path-Objekts verwendet. Die Namenstrennzeichen (Schrägstriche) müssen nicht im variablen Argumentteil enthalten sein:

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

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

5. Pfadinformationen abrufen

Sie können sich das Path-Objekt als Namenselemente als Sequenz vorstellen. Ein PfadString wieE:\examplerticles\java besteht aus drei Namenselementen, d.h. example,articles undjava. Das höchste Element in der Verzeichnisstruktur befindet sich am Index 0, in diesem Fallexample.

Das niedrigste Element in der Verzeichnisstruktur befindet sich am Index[n-1], wobein die Anzahl der Namenselemente im Pfad ist. Dieses niedrigste Element heißtfile name, unabhängig davon, ob es sich um eine tatsächliche Datei handelt oder nicht:

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

    Path fileName = p.getFileName();

    assertEquals("logs", fileName.toString());
}

Zum Abrufen einzelner Elemente nach Index stehen Methoden zur Verfügung:

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

oder eine Teilsequenz des Pfades unter Verwendung dieser Indexbereiche:

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

Jeder Pfad ist einem übergeordneten Pfad odernull zugeordnet, wenn der Pfad keinen übergeordneten Pfad hat. Das übergeordnete Element eines Pfadobjekts besteht aus der Stammkomponente des Pfads (falls vorhanden) und jedem Element im Pfad mit Ausnahme des Dateinamens. Beispielsweise ist der übergeordnete Pfad von/a/b/c/a/b und der von/a ist null:

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

Wir können auch das Wurzelelement eines Pfades erhalten:

@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. Einen Pfad normalisieren

Viele Dateisysteme verwenden die Notation“.”, um das aktuelle Verzeichnis zu bezeichnen, und“..”, um das übergeordnete Verzeichnis zu bezeichnen. Möglicherweise enthält ein Pfad redundante Verzeichnisinformationen.

Betrachten Sie beispielsweise die folgenden Pfadzeichenfolgen:

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

Sie werden alle an denselben Speicherort/example/articles aufgelöst. Die ersten beiden haben Entlassungen, die letzte nicht.

Beim Normalisieren eines Pfads werden Redundanzen entfernt. Zu diesem Zweck wird die OperationPath.normalize()bereitgestellt.

Dieses Beispiel sollte nun selbsterklärend sein:

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

    Path cleanPath = p.normalize();

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

Dieses auch:

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

    Path cleanPath = p.normalize();

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

7. Pfadkonvertierung

Es gibt Vorgänge zum Konvertieren eines Pfads in ein ausgewähltes Präsentationsformat. Um einen Pfad in eine Zeichenfolge zu konvertieren, die über den Browser geöffnet werden kann, verwenden wir die MethodetoUri:

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

Wir können einen Pfad auch in seine absolute Darstellung umwandeln. Die MethodetoAbsolutePath löst einen Pfad für ein Standardverzeichnis des Dateisystems auf:

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

Wenn jedoch festgestellt wird, dass der aufzulösende Pfad bereits absolut ist, gibt die Methode den folgenden Wert zurück:

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

Wir können auch jeden Pfad in sein reales Äquivalent konvertieren, indem wir die MethodetoRealPathaufrufen. Diese Methode versucht, den Pfad aufzulösen, indem die Elemente den tatsächlichen Verzeichnissen und Dateien im Dateisystem zugeordnet werden.

Zeit für die Verwendung der Variablen, die wir im AbschnittSetuperstellt haben und die auf den Heimatort des angemeldeten Benutzers im Dateisystem verweist:

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

    Path realPath = p.toRealPath();

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

Der obige Test sagt nicht viel über das Verhalten dieser Operation aus. Das offensichtlichste Ergebnis ist, dass, wenn der Pfad nicht im Dateisystem vorhanden ist, die Operation einIOException auslöst.

In Ermangelung einer besseren Möglichkeit, diesen Punkt nach Hause zu fahren, werfen Sie einen Blick auf den nächsten Test, der versucht, einen nicht vorhandenen Pfad in einen realen Pfad umzuwandeln:

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

    p.toRealPath();
}

Der Test ist erfolgreich, wenn wir einIOException fangen. Die tatsächliche Unterklasse vonIOException, die diese Operation auslöst, istNoSuchFileException.

8. Pfade verbinden

Das Verbinden von zwei beliebigen Pfaden kann mit derresolve-Methode erreicht werden.

Einfach ausgedrückt, wir können dieresolve-Methode für jedesPath aufrufen und einpartial path als Argument übergeben. Dieser Teilpfad wird an den ursprünglichen Pfad angehängt:

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

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

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

Wenn jedoch die an die Methoderesolve übergebene Pfadzeichenfolge keinpartial path; ist, insbesondere kein absoluter Pfad, wird der übergebene Pfad zurückgegeben:

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

Dasselbe passiert mit jedem Pfad, der ein Wurzelelement hat. Die Pfadzeichenfolge“java” hat kein Stammelement, während die Pfadzeichenfolge“/java” ein Stammelement hat. Wenn Sie einen Pfad mit einem Stammelement übergeben, wird dieser daher wie folgt zurückgegeben:

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

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

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

9. Relativizing Pfade

Der Ausdruckrelativizing bedeutet einfach, einen direkten Pfad zwischen zwei bekannten Pfaden zu erstellen. Wenn wir beispielsweise ein Verzeichnis/example und darin haben, haben wir zwei andere Verzeichnisse, so dass/example/authors und/example/articles gültige Pfade sind.

Der Pfad zuarticles relativ zuauthors würde als“move one level up in the directory hierarchy then into articles directory” oder..rticles: beschrieben

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

Angenommen, wir verschieben das Verzeichnisarticlesin den Ordnerauthors, sodass es sich nicht mehr um Geschwister handelt. Bei den folgenden Relativierungsoperationen wird ein Pfad zwischenexample undarticles erstellt und umgekehrt:

@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. Pfade vergleichen

Die KlassePathhat eine intuitive Implementierung der Methodeequals, mit der wir zwei Pfade auf Gleichheit vergleichen können:

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

Sie können auch prüfen, ob ein Pfad mit einer bestimmten Zeichenfolge beginnt:

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

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

Oder endet mit einer anderen Zeichenfolge:

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

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

11. Fazit

In diesem Artikel haben wir Path-Operationen in der neuen Dateisystem-API (NIO2) gezeigt, die als Teil von Java 7 ausgeliefert wurde, und die meisten davon in Aktion gesehen.

Die in diesem Artikel verwendeten Codebeispiele finden Sie inGithub project des Artikels.