Java NIO2 Path API

1. Übersicht

In diesem Artikel erfahren Sie, wie Sie die neue E / A- Pfad- API (NIO2) in Java verwenden.

Die Pfad- 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. Setup

Die NIO2-Unterstützung ist im Paket java.nio.file enthalten. Wenn Sie Ihr Projekt für die Verwendung der Pfad- APIs einrichten, müssen Sie nur 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 Speicherort in einer beliebigen Umgebung.

Die Paths- Klasse ist der Haupteinstiegspunkt für alle Vorgänge, an denen Dateisystempfade beteiligt sind. 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 Auswirkungen auf das zugrunde liegende Dateisystem und das Dateisystem hat auch keine Auswirkungen darauf, ob sie erfolgreich sind oder fehlschlagen. Dies bedeutet, dass das Übergeben eines nicht vorhandenen Pfads als Parameter einer Pfadoperation keinen Einfluss darauf hat, ob dieser erfolgreich ist oder fehlschlägt.

3. Pfadoperationen

In diesem Abschnitt stellen wir die Hauptsyntax vor, die bei Pfadoperationen verwendet wird. Wie der Name schon sagt, ist die Path- Klasse eine programmatische Darstellung eines Pfads im Dateisystem.

Ein Path- Objekt enthält den Dateinamen und die Verzeichnisliste, die zum Erstellen des Pfads verwendet werden, und wird zum Untersuchen, Suchen und Bearbeiten von Dateien verwendet.

Die Hilfsklasse, java.nio.file.Paths (im Plural) ist der formale Weg zur Schaffung von Pfadobjekten. Es gibt zwei statische Methoden zum Erstellen eines Pfads aus einer Pfadzeichenfolge:

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

Es spielt keine Rolle, ob wir im Pfad String 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 einem java.net.URI- Objekt:

Path path = Paths.get(URI object);

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

4. Einen Pfad erstellen

So erstellen Sie ein Pfadobjekt aus einer Pfadzeichenfolge:

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

Die get- API kann zusätzlich zum ersten Teil (in diesem Fall Artikel ) einen Parameter mit variablen Argumenten für Pfadzeichenfolgenteile (in diesem Fall Artikel und Baeldung ) 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 in den Teil mit den variablen Argumenten aufgenommen werden:

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

5. Abrufen von Pfadinformationen

Sie können sich das Path-Objekt als Namenselemente als Sequenz vorstellen. Ein Pfad String wie E: \ baeldung \ Artikel \ Java besteht aus drei Elementen name dh baeldung , Artikel und Java . Das höchste Element in der Verzeichnisstruktur würde sich am Index 0 befinden, in diesem Fall baeldung .

Das niedrigste Element in der Verzeichnisstruktur befindet sich am Index [n-1] , wobei n die Anzahl der Namenselemente im Pfad ist. Dieses niedrigste Element wird als Dateiname bezeichnet, 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/baeldung/logs"); Path fileName = p.getFileName(); assertEquals("logs", fileName.toString()); }

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

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

oder eine Teilsequenz des Pfads unter Verwendung dieser Indexbereiche:

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

Jeder Pfad ist einem übergeordneten Pfad zugeordnet oder null, 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. Als ein Beispiel kann der übergeordnete Pfad / a / b / c ist / a / b und die von / a ist 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); }

Wir können auch das Wurzelelement eines Pfades erhalten:

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

Viele Dateisysteme verwenden "." Notation zur Bezeichnung des aktuellen Verzeichnisses und ".." zur Bezeichnung des übergeordneten Verzeichnisses. Möglicherweise enthält ein Pfad redundante Verzeichnisinformationen.

Betrachten Sie beispielsweise die folgenden Pfadzeichenfolgen:

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

Sie alle lösen sich an der gleichen Stelle / Baeldung / Artikel . Die ersten beiden haben Redundanzen, die letzten nicht.

Um einen Pfad zu normalisieren, müssen Redundanzen darin entfernt werden. Zu diesem Zweck wird die Operation Path.normalize () bereitgestellt.

Dieses Beispiel sollte jetzt selbsterklärend sein:

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

Dieses auch:

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

7. Pfadkonvertierung

Es gibt Operationen, um einen Pfad in ein ausgewähltes Präsentationsformat zu konvertieren. Um einen Pfad in eine Zeichenfolge zu konvertieren, die über den Browser geöffnet werden kann, verwenden wir die toUri- Methode:

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

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

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

Wenn jedoch festgestellt wird, dass der aufzulösende Pfad bereits absolut ist, gibt die Methode ihn wie folgt zurück:

@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

In diesem Artikel haben wir Pfadoperationen 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 im Github-Projekt des Artikels.