Java NIO.2: Working with Files Using Path and Files - Quiz

Total: 5 questions

1. 

What are Path and Files in NIO.2, and how do you create a Path?

NIO.2 is the java.nio.file API (Java 7). The Path interface describes a path to a file or directory as a sequence of name elements, and the utility class Files with static methods performs file operations: checks, reads, writes, creates, copies, moves, deletes and walks directories. Unlike java.io.File, Files methods throw an exception that names the cause (NoSuchFileException, FileAlreadyExistsException, DirectoryNotEmptyException) instead of returning false.

  • Path.of(first, more...) (Java 11) — the recommended way: Path.of("data", "reports", "2026.txt").
  • Paths.get(...) (Java 7) — the same result, needed in Java 7–10 projects; the docs warn that the Paths class may be deprecated in the future.
  • Path.of(URI) — from a file: URI; for a jar: URI without an open file system you get FileSystemNotFoundException.
  • file.toPath() — migration from the old File; the reverse is path.toFile().

Creating a Path does not touch the disk: the file may not exist, only the syntax is checked (an invalid path gives InvalidPathException). Path parts come from getFileName(), getParent() and getRoot() — all return a Path and may return null (a relative path has no root).

2. 

How do you check that two Path objects point to the same file? What is the difference between equals(), Files.isSameFile(), toAbsolutePath() and toRealPath()?

The reliable way is Files.isSameFile(p1, p2) or comparing toRealPath(): both read the file system. equals(), startsWith() and endsWith() on a Path compare paths as sequences of elements without touching the disk, so a/../b.txt and b.txt are different paths for them.

  • equals() — element by element; case-insensitive on Windows (B.TXT equals b.txt), case-sensitive on Linux and macOS. A path used as a HashMap key behaves differently on different operating systems.
  • normalize() — removes . and .. purely textually: p1.normalize().equals(p2) is already true, but symbolic links are not resolved.
  • toAbsolutePath() — prepends the working directory, does not touch the disk, works for missing files and keeps .. as is.
  • toRealPath() — the canonical path without .. and with links resolved; throws NoSuchFileException for a missing file.
  • Files.isSameFile() — reads the file system and tells whether it is the same file.

If the file does not exist yet but you need an absolute path without .., use p.toAbsolutePath().normalize(). The same normalize() + startsWith(base) pair protects against path traversal when the file name comes from a user.

3. 

How do you read and write a text file with Files? What should you use for a large file, and which charset is used by default?

A small file is read in one call: Files.readString(path) (Java 11) — as one string, Files.readAllLines(path) — as a list of lines, Files.readAllBytes(path) — as a byte array. Write with Files.writeString(path, text) or Files.write(path, lines); without options the file is created or overwritten, and Files.write(path, lines) adds the OS line separator after each line. The file is opened and closed inside the method.

  • Large file: readString() and readAllLines() load everything into memory (a multi-gigabyte log means OutOfMemoryError). Read line by line with Files.lines(path) (Java 8, a lazy Stream<String>) or Files.newBufferedReader(path); write with Files.newBufferedWriter(path). Close all three in try-with-resources.
  • Charset: all text methods of Files without a Charset parameter use UTF-8 on any OS and in any Java version (unlike FileReader up to Java 17).
  • File in another charset: readString() and readAllLines() do not return garbled text, they throw MalformedInputException (for example, Input length = 1 for windows-1251); with Files.lines() the error surfaces while the stream is consumed, as UncheckedIOException. The fix is to pass the real charset: Files.readString(p, Charset.forName("windows-1251")).
4. 

Which Files methods create, copy, move and delete files, and which exceptions do they throw?

Each method throws a specific exception on failure instead of returning false:

  • createFile(), createDirectory() — the target already exists: FileAlreadyExistsException; the parent directory is missing: NoSuchFileException.
  • createDirectories() — creates all missing parent directories; an existing directory is not an error.
  • copy(src, target) — if the target exists, without StandardCopyOption.REPLACE_EXISTING you get FileAlreadyExistsException. A directory is copied empty, without its contents. COPY_ATTRIBUTES copies the modification time and permissions.
  • move(src, target) — renames or moves; the target exists — FileAlreadyExistsException (without REPLACE_EXISTING); ATOMIC_MOVE moves in a single OS operation, across different drives — AtomicMoveNotSupportedException.
  • delete(path) — deletes a file or an empty directory; missing file — NoSuchFileException, non-empty directory — DirectoryNotEmptyException.
  • deleteIfExists(path) — returns false if the file did not exist; for a non-empty directory it also throws DirectoryNotEmptyException.

Checking Files.exists() before the operation is not a guarantee: another program can change the file between the check and the action (TOCTOU). It is safer to perform the operation right away and handle the exception. A temporary file from Files.createTempFile(prefix, suffix) is not deleted automatically — delete it in finally or open it with DELETE_ON_CLOSE.

5. 

What is the difference between Files.list(), Files.walk(), Files.find() and Files.newDirectoryStream()? How do you delete a directory with all its contents?

  • Files.list(dir) — only the direct entries of the directory (dir itself is not included), a Stream<Path>, order not guaranteed; a file instead of a directory gives NotDirectoryException.
  • Files.walk(dir[, maxDepth]) — the whole tree recursively; dir itself comes first, and a directory always comes before its contents.
  • Files.find(dir, maxDepth, (path, attrs) -> ...) — a walk with a filter that already receives the attributes, so no extra Files.isRegularFile() call is needed.
  • Files.newDirectoryStream(dir, "*.{java,kt}") — one level with a glob filter, returns a DirectoryStream<Path> for a for-each loop.

All four keep the directory open, so close them with try-with-resources. walk() and find() do not follow symbolic links without FileVisitOption.FOLLOW_LINKS. Check the extension in a filter as a string: p.getFileName().toString().endsWith(".txt") — p.endsWith(".txt") finds no files at all.

There is no ready-made method to delete a non-empty directory: Files.delete() removes only an empty one. Walk the tree with Files.walk(root), sort with sorted(Comparator.reverseOrder()) so the contents come before their directory, and delete the paths one by one (wrap the IOException inside the lambda in UncheckedIOException). Without reverseOrder() the root comes first, and you immediately get DirectoryNotEmptyException. For very large trees use Files.walkFileTree() and delete the directory in postVisitDirectory().

Page 1 of 1