skip to content

Path & Files API

Path handles path arithmetic (resolve, relativize, normalize) and Files does the operations, including the lazy Files.lines stream and Files.walk traversal. Interviewers care that you close those streams, since they hold an open file handle.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

6

What is the NIO.2 Path interface and how does it relate to the older java.io.File class?

level: juniorimportance: must knowfreq 68%

answer

  1. Path = location only, Files = operations
  2. Path.of / Paths.get to create
  3. Creating a Path never touches disk
  4. IOException subtypes vs boolean false
  5. toPath()/toFile() bridge legacy

basics

~10 s

Path is the modern way (since Java 7) to represent a file or folder location. It replaces the old File class, working together with the Files helper class for cleaner, more reliable file operations.

solid answer

~40 s

Path is an interface in java.nio.file representing a location in a file system (a sequence of name elements plus an optional root). Introduced in Java 7 (NIO.2), it supersedes java.io.File. You create one with Path.of("a","b") or Paths.get(...). Path itself only models the location; actual operations live in the Files utility class (Files.readAllLines, Files.copy, etc.). Compared to File, NIO.2 gives clearer method names, better exceptions (IOException with detail instead of a boolean false), symbolic-link awareness, atomic operations, file attribute views, and pluggable FileSystem providers (e.g. ZIP, in-memory). For bridging legacy code, file.toPath() and path.toFile() convert between the two. In new code prefer Path/Files everywhere.

go deeper

for a junior

Knows Path represents a file/folder location and Files does operations; can create a Path and read a file.

for a middle

Explains the location-vs-operations split, the IOException model vs boolean returns, and File<->Path bridging.

for a senior

Articulates the design rationale (immutability, pluggable FileSystem providers, symbolic-link and attribute support) and migrates legacy java.io.File code deliberately.

for a principal

Reasons about FileSystem provider abstraction (ZIP/in-memory/custom), portability across OSes, and sets team conventions to standardize on NIO.2.

## The problem NIO.2 solves Before Java 7, file handling used `java.io.File`. A `File` object is just an abstract path name; it mixes location data with operations like `delete()`, `mkdir()`, `list()`. The old API had real weaknesses: - **Silent failures:** methods like `file.delete()` or `file.renameTo(...)` return a `boolean`. If they return `false` you have *no idea why* (permission? not found? cross-device move?). - **No symbolic-link control**, no atomic moves, no access to rich file metadata (owner, POSIX permissions, creation time). - **One hard-coded file system** — you couldn't treat a ZIP archive or an in-memory store as a file system. **NIO.2** (New I/O 2, JSR 203, Java 7) introduced the `java.nio.file` package to fix all of this. ## Path: just the location `Path` is an **interface** representing a path in *some* file system: an optional **root** (like `/` or `C:\`) plus an ordered sequence of **name elements** (the directories and final file name). Key idea: a `Path` is *purely a location* — creating one does **not** touch the disk, and the file it points to need not exist. You obtain a `Path` via: ```java Path p = Path.of("/etc", "hosts"); // preferred, Java 11+ Path q = Paths.get("/etc/hosts"); // older factory, identical result ``` A `Path` exposes location queries: `getFileName()`, `getParent()`, `getRoot()`, `getNameCount()`, `isAbsolute()`. These are pure string/structure operations — still no disk access. ## Files: the operations Where `File` bundled operations into the object, NIO.2 **separates** them into the static utility class `java.nio.file.Files`. You pass a `Path` to a `Files` method to actually do work: `Files.exists(p)`, `Files.createDirectories(p)`, `Files.copy(src,dst)`, `Files.delete(p)`, `Files.readAllLines(p)`. These throw `IOException` (a *checked* exception) with a descriptive subtype — `NoSuchFileException`, `FileAlreadyExistsException`, `AccessDeniedException` — instead of a meaningless `false`. ## Why the split helps Separating *location* (`Path`) from *operations* (`Files`) keeps `Path` immutable and cheap, and lets the same `Path` work across pluggable `FileSystem` providers (default OS file system, ZIP file system, third-party in-memory systems). A `Path` always knows which `FileSystem` produced it via `path.getFileSystem()`. ## Bridging old and new Legacy APIs that still return `File` can be converted: `File#toPath()` and `Path#toFile()`. Use this only at the boundary; write new logic against `Path`/`Files`. ## Bottom line - `Path` = an immutable, file-system-aware **address**. - `Files` = the **verbs** acting on that address, with real exceptions. - Prefer them over `java.io.File` in all new code.

  • Why does Files.delete throw an exception while File.delete returns a boolean, and which is better?
    Files.delete throws a typed IOException (e.g. NoSuchFileException) so the caller learns *why* it failed and must handle it. File.delete swallows the reason into false. The exception model is better because failures are explicit and diagnosable.
  • How do you convert between File and Path?
    file.toPath() goes from java.io.File to Path; path.toFile() goes back. Use these only to interoperate with legacy APIs.

saying these in an interview costs you the question

  • Thinking creating a Path checks that the file exists
  • Calling delete/copy directly on Path (those are on Files)
  • Believing File and Path are interchangeable in behavior (File returns booleans, Path/Files throws)
  • Saying Path is a class — it is an interface

context

open as a page

Explain Path.resolve, Path.relativize, and Path.normalize — what does each do and when would you use them?

level: middleimportance: must knowfreq 62%

basics

~20 s

resolve joins two paths (base + child). relativize finds the route from one path to another. normalize cleans up redundant . and .. segments. They are pure string-style operations that do not touch the disk.

open as a page

What are the key Files methods for creating, copying, moving, and deleting files and directories, and what options control their behavior?

level: middleimportance: should knowfreq 52%

basics

~10 s

Files.createFile/createDirectory/createDirectories make files and folders; Files.copy copies; Files.move moves or renames; Files.delete and deleteIfExists remove. Options like REPLACE_EXISTING, COPY_ATTRIBUTES, and ATOMIC_MOVE tweak how copy and move behave.

open as a page

How does Files.lines() differ from Files.readAllLines(), and what must you be careful about when using it?

level: seniorimportance: should knowfreq 48%

basics

~20 s

Files.readAllLines reads the whole file into a List in memory at once. Files.lines returns a lazy Stream that reads line-by-line, so it handles huge files, but you must close the stream (use try-with-resources) because it holds an open file handle.

open as a page

Compare Files.walk() and Files.walkFileTree() for directory traversal. When would you choose each, and what are the pitfalls?

level: seniorimportance: should knowfreq 44%

basics

~20 s

Files.walk returns a lazy Stream of all paths under a directory, great for simple filtering — but you must close it. Files.walkFileTree uses a visitor callback giving fine control over each file, directory entry/exit, and errors, which is better for complex traversals like recursive delete.

open as a page

How do you read file attributes (size, timestamps, type, POSIX permissions) with NIO.2, and what is the advantage of the attribute-views model?

level: seniorimportance: nice to knowfreq 30%

basics

~20 s

Use the Files helpers like size(), isDirectory(), getLastModifiedTime(), or read a whole bundle with Files.readAttributes(path, BasicFileAttributes.class). For OS-specific data like Unix permissions you request a PosixFileAttributes view. One bulk read is cheaper than many separate calls.

open as a page