Java Path (and a quick note on Paths)¶
Pathis the main interface injava.nio.filethat models a filesystem path (like"images/cat.png"or"/usr/local/bin").- About
Paths: since Java 11, you can usePath.of(...)instead ofPaths.get(...). They do the same thing. Because of that, this guide usesPath.ofand ignoresPaths.
Quick glossary (beginner-friendly)¶
- Absolute path: a full address from the filesystem root, e.g.
"/home/alex/report.txt"(Unix) or"C:\Users\Alex\report.txt"(Windows). It doesn’t depend on the “current folder”. - Relative path: a path relative to a base (usually the app’s current working directory), e.g.
"docs/report.txt"or"../images/logo.png". - Root: the topmost starting point of the filesystem (
"/"on Unix; a drive like"C:\"on Windows). - Normalize: clean a path by removing
.(current dir) and resolving..(go up one folder) without touching the disk. - Resolve: join paths like URLs: base.resolve(child) → “append” child to base.
- Relativize: create a relative path that goes from one path to another.
- Real path: an absolute, normalized path with symlinks resolved on disk.
Creating Path instances¶
Path.of(String first, String... more)¶
Create a path from one or more parts.
Path p1 = Path.of("images", "icons", "cat.png"); // "images/icons/cat.png"
Path p2 = Path.of("/usr", "local", "bin"); // "/usr/local/bin" (absolute on Unix)
Output examples
p1.toString()→"images/icons/cat.png"p2.isAbsolute()→true
Use this instead of
Paths.get(...)on Java 11+.
Reading path structure¶
getFileName()¶
Last element of the path (the “leaf”).
getParent()¶
Everything except the last element (or null if none).
getRoot()¶
The root component (or null if relative).
Path p1 = Path.of("/var/log/system.log");
Path p2 = Path.of("docs/readme.md");
p1.getRoot().toString(); // "/"
p2.getRoot(); // null (relative path)
getNameCount() and getName(int index)¶
Count and access individual name elements (0-based, root excluded).
Path p = Path.of("/usr/local/bin");
p.getNameCount(); // 3 ("usr","local","bin")
p.getName(1).toString(); // "local"
subpath(int beginIndex, int endIndex)¶
Slice out a portion of the names (root not included).
Checking path properties¶
isAbsolute()¶
Is this path absolute?
startsWith(...) / endsWith(...)¶
Compare by path elements (not plain string).
Path p = Path.of("src/main/java/App.java");
p.startsWith("src"); // true
p.endsWith("App.java"); // true
p.endsWith(Path.of("java", "App.java")); // true
Transforming paths (no filesystem access)¶
normalize()¶
Remove . and fold .. where possible.
resolve(String|Path other)¶
Append other to this path (unless other is absolute, then other is returned).
Path base = Path.of("/home/alex");
base.resolve("docs/report.txt").toString(); // "/home/alex/docs/report.txt"
base.resolve("/etc/hosts").toString(); // "/etc/hosts" (absolute wins)
resolveSibling(String|Path other)¶
Replace the last element with other.
Path p = Path.of("/home/alex/docs/report.txt");
p.resolveSibling("notes.txt").toString(); // "/home/alex/docs/notes.txt"
relativize(Path other)¶
Create a relative path from this to other. Both must be both absolute or both relative, and on the same root/drive.
Path a = Path.of("/home/alex/docs");
Path b = Path.of("/home/alex/images/pic.png");
a.relativize(b).toString(); // "../images/pic.png"
Converting paths¶
toAbsolutePath()¶
Turn a relative path into an absolute one using the current working directory; already-absolute paths are returned as-is. (No disk access.)
toRealPath(LinkOption... options)¶
Return the real absolute path: normalized and with symlinks resolved. Touches the filesystem and can throw if missing.
If you pass
LinkOption.NOFOLLOW_LINKS, it won’t resolve symlinks (still checks existence).
toUri()¶
Convert to a file: URI.
toFile()¶
Convert to the old java.io.File object.
Interop & utilities¶
iterator() (implements Iterable<Path>)¶
Iterate path elements.
compareTo(Path other) (and equals, hashCode)¶
Lexicographic comparison based on the filesystem’s rules.
getFileSystem()¶
The FileSystem this Path belongs to (useful with custom/ZIP filesystems).
Common Files helpers you’ll often use with Path (not methods on Path, but handy)¶
Files.exists(Path.of("notes.txt")); // true/false
Files.createDirectories(Path.of("out/logs")); // create all missing dirs
Files.copy(srcPath, destPath, REPLACE_EXISTING); // copy a file
Files.move(srcPath, destPath, ATOMIC_MOVE); // move/rename
Files.delete(Path.of("old.txt")); // delete
Files.readString(Path.of("data.txt")); // read whole file as String
Files.writeString(Path.of("out.txt"), "hello"); // write text
Windows vs. Unix notes (gotchas)¶
- Roots: Unix root is
"/". Windows roots are drives like"C:\"and UNC roots like"\\server\share". - Separators:
Pathuses the platform’s separator under the hood. You can write either'/'or'\'in string literals, but preferPath.of("a","b","c")to stay portable. - Relativize/resolve: You can’t relativize/resolve across different roots/drives.
Mini reference (method → what it does → example I/O)¶
| Method | What it does | Example input → output |
|---|---|---|
Path.of("a","b","c") |
Make a path from parts | → "a/b/c" |
getFileName() |
Last path segment | "/x/y/z.txt" → "z.txt" |
getParent() |
Path without the last segment | "/x/y/z.txt" → "/x/y" |
getRoot() |
The root component or null |
"/x/y" → "/"; "x/y" → null |
getNameCount() |
Number of segments (no root) | "/a/b/c" → 3 |
getName(i) |
Segment at index i |
"/a/b/c" & i=1 → "b" |
subpath(i,j) |
Slice of segments [i,j) |
"/a/b/c/d", (1,3) → "b/c" |
isAbsolute() |
Is it a full path from the root? | "/a/b" → true; "a/b" → false |
startsWith(x) |
Starts with segment(s) x? |
"src/main/App.java" & "src" → true |
endsWith(x) |
Ends with segment(s) x? |
"src/main/App.java" & "App.java" → true |
normalize() |
Remove . and fold .. |
"a/./b/../c" → "a/c" |
resolve(x) |
Append x (unless x is absolute) |
"/home/a" + "docs/r.txt" → "/home/a/docs/r.txt" |
resolveSibling(x) |
Replace the last segment | "/a/b/c.txt" + "d.txt" → "/a/b/d.txt" |
relativize(other) |
Path from this to other |
"/a/b" → "/a/c/d" gives "../c/d" |
toAbsolutePath() |
Make absolute using CWD | "logs/app.log" → "/…/logs/app.log" |
toRealPath() |
Absolute, normalized, resolve symlinks (touches disk) | "link/file" → "/actual/file" |
toUri() |
Convert to file: URI |
"/tmp/t.txt" → "file:///tmp/t.txt" |
toFile() |
Convert to java.io.File |
"docs/readme.md" → File("docs/readme.md") |
iterator() |
Iterate segments | "a/b/c" → "a", "b", "c" |
compareTo() |
Order paths lexicographically | "a" vs "b" → < 0 |
Tiny end-to-end example¶
Path base = Path.of("/home/alex/projects");
Path rel = Path.of("demo/../lib/utils.java"); // relative
Path norm = rel.normalize(); // "lib/utils.java"
Path abs = base.resolve(norm); // "/home/alex/projects/lib/utils.java"
Path here = Path.of(".").toAbsolutePath(); // absolute CWD
Path linkFree = abs.toRealPath(); // resolves symlinks (if any; hits disk)
Path back = base.relativize(linkFree); // relative from base to real file
Typical outputs
norm.toString()→"lib/utils.java"abs.toString()→"/home/alex/projects/lib/utils.java"back.toString()→"lib/utils.java"
Important behaviors & gotchas¶
-
Relative vs Absolute
Path.of("docs/file.txt")is relative: it depends on the program’s current working directory.Path.of("/home/user/docs/file.txt")(Unix) orPath.of("C:\\Users\\Alex\\file.txt")(Windows) is absolute: it always points to the same place, no matter where the program is run.
-
Normalize doesn’t touch the disk
normalize()just cleans up the string form of the path (.and..).- It doesn’t check if the file exists.
-
Real path touches the disk
toRealPath()does check the filesystem.- It resolves symlinks, checks existence, and can throw exceptions if the file isn’t there.
-
Resolve vs. Relativize confusion
resolve(child)→ go deeper into the tree.relativize(other)→ calculate the path between two paths.- You can’t
relativizeacross different drives/roots (C:\vsD:\on Windows, or/vs a network share on Unix).
-
StartsWith/EndsWith are by segments, not plain strings
"src/main/java/App.java".endsWith("java")→ false (last segment is"App.java")."src/main/java/App.java".endsWith("App.java")→ true.
-
Iterating excludes root
/usr/local/binwill give elements"usr","local","bin"— the root/is not included.
-
Cross-platform differences
- On Windows: roots are drives (
C:\), case-insensitive by default. - On Unix: root is
/, case-sensitive.
- On Windows: roots are drives (
Bottom line¶
- Use
Pathinstead of string concatenation: It handles separators, OS differences, and path logic safely. - Prefer
Path.of(...)(Java 11+) overPaths.get(...). - Use
normalize()when you want a clean path string. - Use
toRealPath()only if you need the true location on disk (and are ready to handle errors). - Combine with
Filesclass for actual file operations (exists,read,write,delete). - Remember:
Pathitself is just a description of a location — it doesn’t create, delete, or read files.