Files Class
java.nio.file.Files is a utility class introduced in Java 7 containing over 70 static methods that perform all file system operations on Path objects: reading and writing file content, querying and setting file metadata, creating and deleting files and directories, copying and moving, directory listing and recursive traversal, checking permissions and existence, managing symbolic links, and obtaining channels and streams. Files is the NIO.2 replacement for the operations previously handled by java.io.File's mutation methods (which return boolean on failure) and for the InputStream/OutputStream factory pattern used with java.io streams. Every Files method throws IOException (or a subclass like NoSuchFileException, FileAlreadyExistsException, DirectoryNotEmptyException, or AccessDeniedException) rather than returning boolean, making error handling explicit and unambiguous. This entry covers every major category of Files method in depth, the complete set of StandardOpenOption and StandardCopyOption values, atomic operations and their filesystem-level semantics, bulk read/write convenience methods, the directory traversal API including Files.walk, Files.find, and Files.walkFileTree, permission and attribute manipulation, and the interplay between Files methods and the underlying OS system calls.
Content Reading and Writing — All Forms
// ── Reading: all forms ───────────────────────────────────────────────
Path p = Path.of("data.txt");
// Entire file as byte array — binary or small files:
byte[] bytes = Files.readAllBytes(p);
System.out.println("Bytes: " + bytes.length);
// Entire file as String — small text files (Java 11+):
String text = Files.readString(p, StandardCharsets.UTF_8);
System.out.println("Chars: " + text.length());
// All lines as List<String> — loads entire file into memory:
List<String> lines = Files.readAllLines(p, StandardCharsets.UTF_8);
System.out.println("Lines: " + lines.size());
// Lazy stream of lines — for large files (MUST close):
try (Stream<String> stream = Files.lines(p, StandardCharsets.UTF_8)) {
long errorCount = stream.filter(l -> l.contains("ERROR")).count();
System.out.println("Errors: " + errorCount);
} // stream.close() releases the underlying file handle
// InputStream for binary streaming:
try (InputStream is = Files.newInputStream(p, StandardOpenOption.READ)) {
byte[] buf = new byte[4096];
int n;
while ((n = is.read(buf)) != -1) processBytes(buf, n);
}
// BufferedReader for text streaming:
try (BufferedReader br = Files.newBufferedReader(p, StandardCharsets.UTF_8)) {
String line;
while ((line = br.readLine()) != null) processLine(line);
}
// ── Writing: all forms ────────────────────────────────────────────────
Path out = Path.of("output.txt");
// Byte array — binary output or pre-encoded text:
Files.write(out, "Hello
".getBytes(StandardCharsets.UTF_8));
// String — clean text output (Java 11+):
Files.writeString(out, "Hello, World!
", StandardCharsets.UTF_8);
// Lines — each element followed by system line separator:
Files.write(out, List.of("Line 1", "Line 2", "Line 3"), StandardCharsets.UTF_8);
// OutputStream for large/streaming binary:
try (OutputStream os = Files.newOutputStream(out,
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
byte[] buf = new byte[65536];
while (hasMoreData()) { os.write(buf, 0, fillBuffer(buf)); }
}
// BufferedWriter for large/streaming text:
try (BufferedWriter bw = Files.newBufferedWriter(out, StandardCharsets.UTF_8)) {
for (Record r : getRecords()) {
bw.write(r.toCsv());
bw.newLine();
}
}
// ── OpenOptions — controlling creation and truncation ────────────────
// Default (create or overwrite):
Files.writeString(out, "content"); // same as CREATE + TRUNCATE_EXISTING + WRITE
// Fail if exists — atomic exclusive create:
try {
Files.writeString(out, "content",
StandardOpenOption.CREATE_NEW, // throws FileAlreadyExistsException if exists
StandardOpenOption.WRITE);
} catch (FileAlreadyExistsException e) {
System.out.println("File already exists: " + e.getFile());
}
// Append to existing:
Files.writeString(out, "new line
",
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
// Sync to hardware on every write (expensive but durable):
try (OutputStream os = Files.newOutputStream(out,
StandardOpenOption.CREATE, StandardOpenOption.WRITE,
StandardOpenOption.SYNC)) { // O_SYNC
os.write(criticalData); // each write flushes to hardware
}Existence, Metadata, Create, Delete, Copy, and Move
// ── Existence and type tests ──────────────────────────────────────────
Path p = Path.of("/home/user/file.txt");
System.out.println(Files.exists(p)); // follows symlinks
System.out.println(Files.exists(p, LinkOption.NOFOLLOW_LINKS)); // tests symlink itself
System.out.println(Files.notExists(p)); // false if IOException (not !exists!)
System.out.println(Files.isRegularFile(p));
System.out.println(Files.isDirectory(p));
System.out.println(Files.isSymbolicLink(p));
System.out.println(Files.isReadable(p));
System.out.println(Files.isWritable(p));
System.out.println(Files.isExecutable(p));
System.out.println(Files.isHidden(p));
System.out.println(Files.size(p)); // throws NoSuchFileException if missing
System.out.println(Files.getLastModifiedTime(p)); // FileTime
Files.setLastModifiedTime(p, FileTime.from(Instant.now()));
// ── Create operations ─────────────────────────────────────────────────
// Atomic exclusive create (no TOCTOU race):
try {
Files.createFile(Path.of("/tmp/lock.flag")); // atomic: create OR exception
} catch (FileAlreadyExistsException e) {
System.out.println("Lock already held");
}
// Create directories:
Files.createDirectory(Path.of("/tmp/single")); // one level only
Files.createDirectories(Path.of("/tmp/a/b/c/d")); // all missing levels, idempotent
// Temp files:
Path tmpFile = Files.createTempFile("prefix-", ".tmp"); // in system temp dir
Path tmpFileInDir = Files.createTempFile(Path.of("/work"), "tmp-", null);
Path tmpDir = Files.createTempDirectory("myapp-");
try {
doWork(tmpFile);
} finally {
Files.deleteIfExists(tmpFile);
}
// ── Delete operations ─────────────────────────────────────────────────
try {
Files.delete(Path.of("/tmp/file.txt")); // precise exceptions:
} catch (NoSuchFileException e) {
System.err.println("Didn't exist: " + e.getFile());
} catch (DirectoryNotEmptyException e) {
System.err.println("Directory not empty: " + e.getFile());
} catch (AccessDeniedException e) {
System.err.println("Permission denied: " + e.getFile());
}
boolean deleted = Files.deleteIfExists(Path.of("/tmp/maybe.txt")); // idempotent
System.out.println("Was deleted: " + deleted); // false if didn't exist
// ── Copy operations ───────────────────────────────────────────────────
Path src = Path.of("/source/data.bin");
Path dst = Path.of("/dest/data.bin");
Files.copy(src, dst); // throws FileAlreadyExistsException if dst exists
Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING); // overwrite
Files.copy(src, dst,
StandardCopyOption.REPLACE_EXISTING,
StandardCopyOption.COPY_ATTRIBUTES); // also copy timestamps, permissions
// Copy from InputStream to file (download pattern):
try (InputStream download = new URL("https://example.com/file.zip").openStream()) {
Files.copy(download, Path.of("/tmp/file.zip"), StandardCopyOption.REPLACE_EXISTING);
}
// Copy from file to OutputStream:
try (OutputStream out = response.getOutputStream()) {
Files.copy(Path.of("/static/index.html"), out);
}
// ── Move and atomic rename ────────────────────────────────────────────
Path src2 = Path.of("/tmp/new-data.bin");
Path dst2 = Path.of("/var/data/data.bin");
// Simple rename (same filesystem — atomic on POSIX):
Files.move(src2, dst2, StandardCopyOption.REPLACE_EXISTING);
// Explicit atomic move (throws AtomicMoveNotSupportedException if cross-filesystem):
try {
Files.move(src2, dst2,
StandardCopyOption.ATOMIC_MOVE,
StandardCopyOption.REPLACE_EXISTING);
} catch (AtomicMoveNotSupportedException e) {
// Fall back to copy-then-delete (non-atomic):
Files.copy(src2, dst2, StandardCopyOption.REPLACE_EXISTING);
Files.delete(src2);
}
// Safe update pattern: write to temp, atomic rename to target:
Path target = Path.of("/config/settings.json");
Path temp = Files.createTempFile(target.getParent(), ".tmp-", null);
try {
Files.writeString(temp, newConfigJson, StandardCharsets.UTF_8);
Files.move(temp, target, StandardCopyOption.ATOMIC_MOVE,
StandardCopyOption.REPLACE_EXISTING);
} catch (Exception e) {
Files.deleteIfExists(temp);
throw e;
}Directory Traversal, Attributes, Symlinks, and Permissions
// ── Files.list — lazy directory listing ──────────────────────────────
Path dir = Path.of("/home/user");
// Single directory, lazy:
try (Stream<Path> entries = Files.list(dir)) {
entries.filter(Files::isRegularFile)
.sorted()
.forEach(System.out::println);
}
// Count entries without loading all into memory:
try (Stream<Path> entries = Files.list(dir)) {
long count = entries.count();
System.out.println("Entries: " + count);
}
// ── Files.walk — recursive lazy traversal ────────────────────────────
Path project = Path.of("/home/user/project");
// All Java files, any depth:
try (Stream<Path> walk = Files.walk(project)) {
walk.filter(p -> p.toString().endsWith(".java"))
.sorted()
.forEach(System.out::println);
}
// Limited depth — direct children only (same as list):
try (Stream<Path> walk = Files.walk(project, 1)) {
walk.skip(1) // skip the root itself
.forEach(System.out::println);
}
// Total size of directory tree:
try (Stream<Path> walk = Files.walk(project)) {
long totalSize = walk
.filter(Files::isRegularFile)
.mapToLong(p -> { try { return Files.size(p); }
catch (IOException e) { return 0L; } })
.sum();
System.out.printf("Total: %.2f MB%n", totalSize / 1e6);
}
// ── Files.find — walk + attribute filter in one pass ──────────────────
FileTime oneWeekAgo = FileTime.from(Instant.now().minus(7, ChronoUnit.DAYS));
// Find large files modified in the last week:
try (Stream<Path> found = Files.find(project, Integer.MAX_VALUE,
(path, attrs) ->
attrs.isRegularFile() &&
attrs.size() > 1_000_000 &&
attrs.lastModifiedTime().compareTo(oneWeekAgo) > 0)) {
found.forEach(p -> {
try { System.out.printf("%s (%,d bytes)%n", p, Files.size(p)); }
catch (IOException e) {}
});
}
// ── walkFileTree — delete directory tree ─────────────────────────────
void deleteTree(Path root) throws IOException {
Files.walkFileTree(root, new SimpleFileVisitor<>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc)
throws IOException {
if (exc != null) throw exc;
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
}
// ── Rich attribute reading ─────────────────────────────────────────────
Path file = Path.of("/home/user/data.txt");
// Basic attributes — one stat() call:
BasicFileAttributes basic = Files.readAttributes(file, BasicFileAttributes.class);
System.out.println("Size: " + basic.size());
System.out.println("Created: " + basic.creationTime());
System.out.println("Modified: " + basic.lastModifiedTime());
System.out.println("Accessed: " + basic.lastAccessTime());
System.out.println("Is file: " + basic.isRegularFile());
System.out.println("Is dir: " + basic.isDirectory());
System.out.println("Is symlink: " + basic.isSymbolicLink());
System.out.println("File key: " + basic.fileKey()); // inode number on Unix
// POSIX attributes (Unix only):
PosixFileAttributes posix = Files.readAttributes(file, PosixFileAttributes.class);
System.out.println("Owner: " + posix.owner().getName());
System.out.println("Group: " + posix.group().getName());
Set<PosixFilePermission> perms = posix.permissions();
System.out.println("Perms: " + PosixFilePermissions.toString(perms)); // e.g., "rwxr-x---"
// Setting permissions:
Files.setPosixFilePermissions(file,
PosixFilePermissions.fromString("rw-r--r--"));
// ── Symbolic links ─────────────────────────────────────────────────────
Path link = Path.of("/home/user/link");
Path target = Path.of("/data/actual-file.txt");
Files.createSymbolicLink(link, target); // create symlink
Path where = Files.readSymbolicLink(link); // where does it point?
System.out.println("Link → " + where); // /data/actual-file.txt
// Check without following:
System.out.println(Files.isSymbolicLink(link)); // true
System.out.println(Files.exists(link, LinkOption.NOFOLLOW_LINKS)); // true (link exists)
System.out.println(Files.exists(link)); // true only if target exists
// ── FileStore — disk space information ───────────────────────────────
FileStore store = Files.getFileStore(file);
System.out.printf("Drive: %s Total: %.1fGB Free: %.1fGB%n",
store.name(),
store.getTotalSpace() / 1e9,
store.getUsableSpace() / 1e9);