Java NIO2 Path API

1. Översikt

I den här artikeln lär vi oss hur du använder det nya I / O (NIO2) Path API i Java.

De Path API: er i NIO2 utgör en av de viktigaste nya funktionella områden som medföljde Java 7 och i synnerhet en delmängd av det nya filsystemet API tillsammans File API: er.

2. Inställning

NIO2-stödet ingår i paketet java.nio.file . Så att ställa in ditt projekt för att använda Path API: er är bara en fråga om att importera allt i detta paket:

import java.nio.file.*;

Eftersom kodproverna i den här artikeln förmodligen kommer att köras i olika miljöer, låt oss ta hand om användarens hemkatalog:

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

Denna variabel pekar på en giltig plats i alla miljöer.

Den Paths klassen är den viktigaste inkörsporten till all verksamhet som rör filsystem vägar. Det låter oss skapa och manipulera sökvägar till filer och kataloger.

Det är värt att notera att banoperationer huvudsakligen är syntaktiska till sin natur; de har ingen effekt på det underliggande filsystemet och inte heller har filsystemet någon effekt på om de lyckas eller misslyckas. Det betyder att att skicka en obefintlig sökväg som en parameter för en vägoperation inte har någon betydelse för om den lyckas eller misslyckas.

3. Banoperationer

I det här avsnittet presenterar vi huvudsyntaxen som används i sökoperationer. Som namnet antyder är Path- klassen en programmatisk representation av en sökväg i filsystemet.

Ett sökobjekt innehåller filnamnet och kataloglistan som används för att konstruera sökvägen och används för att undersöka, lokalisera och manipulera filer.

Hjälparklassen java.nio.file.Paths (i pluralform) är det formella sättet att skapa Path- objekt. Den har två statiska metoder för att skapa en bana från en stig sträng:

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

Oavsett om vi använder en framåt eller bakåtvänd snedstreck i sökvägen String spelar ingen roll, API löser den här parametern enligt det underliggande filsystemets krav.

Och från ett java.net.URI- objekt:

Path path = Paths.get(URI object);

Vi kan nu gå vidare och se dessa i aktion.

4. Skapa en sökväg

Så här skapar du ett sökobjekt från en söksträng:

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

Det get API kan ta en variabel argument parametern path sträng delar (i detta fall, artiklar och baeldung ) utöver den första delen (i detta fall, artiklar ).

Om vi ​​tillhandahåller dessa delar istället för en fullständig söksträng, kommer de att användas för att konstruera Path-objektet, vi behöver inte inkludera namnseparatorer (snedstreck) i variabelargumentdelen:

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

5. Hämta sökinformation

Du kan tänka på Path-objektet som namnelement som en sekvens. En söksträng som E: \ baeldung \ articles \ java består av tre namnelement , dvs baeldung , artiklar och java . Det högsta elementet i katalogstrukturen ligger i index 0, i detta fall är baeldung .

Det lägsta elementet i katalogstrukturen ligger i index [n-1] , där n är antalet namnelement i sökvägen. Detta lägsta element kallas filnamnet oavsett om det är en faktisk fil eller inte:

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

Metoder finns för att hämta enskilda element efter 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()); }

eller en undersekvens av sökvägen med hjälp av dessa indexområden:

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

Varje sökväg är associerad med en överordnad sökväg eller null om sökvägen inte har någon förälder. Föräldern till ett sökobjekt består av banans rotkomponent, om någon, och varje element i sökvägen förutom filnamnet. Som ett exempel, moderbanan för / a / b / c är / a / b och den för / a är 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); }

Vi kan också få rotelementet till en sökväg:

@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. Normalisera en sökväg

Många filsystem använder “.” notation för att beteckna aktuell katalog och “..” för att beteckna överordnad katalog. Du kan ha en situation där en sökväg innehåller överflödig kataloginformation.

Tänk till exempel på följande strängar:

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

They all resolve to the same location /baeldung/articles. The first two have redundancies while the last one does not.

Normalizing a path involves removing redundancies in it. The Path.normalize() operation is provided for this purpose.

This example should now be self-explanatory:

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

This one too:

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

7. Path Conversion

There are operations to convert a path to a chosen presentation format. To convert any path into a string that can be opened from the browser, we use the toUri method:

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

We can also convert a path to its absolute representation. The toAbsolutePath method resolves a path against a file system default directory:

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

However, when the path to be resolved is detected to be already absolute, the method returns it as is:

@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

I den här artikeln visade vi Path-operationer i det nya filsystemet API (NIO2) som levererades som en del av Java 7 och såg de flesta av dem i aktion.

Kodproverna som används i den här artikeln finns i artikelns Github-projekt.