What are the key Files methods for creating, copying, moving, and deleting files and directories, and what options control their behavior?
answer
- createDirectories = mkdir -p, idempotent
- REPLACE_EXISTING overwrites target
- ATOMIC_MOVE = same FileStore only
- delete throws if missing; deleteIfExists doesn't
- Non-empty dir delete = DirectoryNotEmptyException
- copy of a dir is shallow
basics
~10 sFiles.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.
solid answer
~40 sCreation: createFile(p) makes an empty file (fails if it exists), createDirectory(p) makes one directory (parent must exist), and createDirectories(p) makes the whole missing chain (like mkdir -p, and it is fine if it already exists). Copy/move: Files.copy(src,dst) and Files.move(src,dst) take varargs CopyOption / StandardCopyOption flags: REPLACE_EXISTING overwrites the target, COPY_ATTRIBUTES preserves metadata, and ATOMIC_MOVE (move only) guarantees the move is all-or-nothing, typically only within the same file store. Deletion: delete(p) throws NoSuchFileException if absent, while deleteIfExists(p) returns a boolean and never throws for absence; deleting a non-empty directory throws DirectoryNotEmptyException — you must walk and delete children first. All throw typed IOExceptions, so you can react to specific failures, and operations are symbolic-link aware (NOFOLLOW_LINKS where relevant).
go deeper
Names create/copy/move/delete methods and knows createDirectories makes parents.
Explains the key options (REPLACE_EXISTING, COPY_ATTRIBUTES, ATOMIC_MOVE) and delete vs deleteIfExists and the non-empty-dir rule.
Uses ATOMIC_MOVE for atomic publish, handles typed exceptions for precise recovery, and knows copy is shallow on directories.
Designs robust, idempotent file pipelines accounting for FileStore boundaries, partial-failure recovery, and symlink semantics across platforms.
## The CRUD verbs of the file system `java.nio.file.Files` is the static utility holding all the *actions*; you pass it `Path`s. Each method throws a **checked `IOException`** with a meaningful subtype on failure, which is the big improvement over `java.io.File`'s boolean returns. ## Creating ```java Files.createFile(path); // empty file; fails if it already exists Files.createDirectory(path); // ONE directory; parent must already exist Files.createDirectories(path); // creates ALL missing parents (mkdir -p); OK if present ``` - `createFile` throws `FileAlreadyExistsException` if the target exists. - `createDirectory` throws `NoSuchFileException` if the parent is missing. - `createDirectories` is the forgiving one: it builds the whole chain and does **not** complain if the directory already exists — the usual choice when ensuring a target folder. - There are also `createTempFile` / `createTempDirectory` for scratch space. ## Copying — Files.copy ```java Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); ``` The trailing varargs are `CopyOption`s. The important `StandardCopyOption` values: - **REPLACE_EXISTING** — overwrite `dst` if it exists; without it, an existing target causes `FileAlreadyExistsException`. - **COPY_ATTRIBUTES** — carry over file metadata (timestamps, etc.) where supported. - `LinkOption.NOFOLLOW_LINKS` — copy the symbolic link itself rather than its target. There are also overloads to copy from an `InputStream` to a `Path` and from a `Path` to an `OutputStream`. Copying a directory copies the directory entry only, **not** its contents recursively — for a deep copy you walk the tree yourself. ## Moving / renaming — Files.move ```java Files.move(src, dst, StandardCopyOption.REPLACE_EXISTING); ``` Move relocates or renames. Same `REPLACE_EXISTING` semantics, plus: - **ATOMIC_MOVE** — the move is performed as a single atomic file-system operation (no observable half-state). This typically works **only within the same `FileStore`** (same disk/partition); crossing file stores throws `AtomicMoveNotSupportedException`. It is the right tool for the classic *write-to-temp-then-rename-into-place* publish pattern. ## Deleting ```java Files.delete(path); // throws NoSuchFileException if absent boolean removed = Files.deleteIfExists(path); // false if absent, no throw ``` - `delete` is strict: absence is an error (`NoSuchFileException`). - `deleteIfExists` is lenient: returns `false` when nothing was there, ideal in idempotent cleanup. - **A non-empty directory cannot be deleted** — you get `DirectoryNotEmptyException`. To remove a tree, traverse it (e.g. `Files.walk(...)` sorted in reverse so children go before parents, or `walkFileTree`) and delete each entry. ## Why typed exceptions matter Because each failure mode is its own exception subtype, you can write precise recovery: catch `FileAlreadyExistsException` to skip, `AccessDeniedException` to report a permission problem, `AtomicMoveNotSupportedException` to fall back to a non-atomic copy+delete. This is far more robust than inspecting a bare `false`. ## Quick reference | Action | Method | Notable options / behavior | |---|---|---| | New empty file | `createFile` | fails if exists | | New dir (one) | `createDirectory` | parent must exist | | New dir chain | `createDirectories` | mkdir -p, idempotent | | Copy | `copy` | REPLACE_EXISTING, COPY_ATTRIBUTES | | Move/rename | `move` | REPLACE_EXISTING, ATOMIC_MOVE (same store) | | Delete strict | `delete` | throws if missing / non-empty dir | | Delete lenient | `deleteIfExists` | boolean, no throw on absence |
- How do you safely 'publish' a file so readers never see a half-written version?Write the full content to a temporary file in the same directory, then Files.move it onto the final name with ATOMIC_MOVE (and REPLACE_EXISTING). Because both are in the same FileStore the rename is atomic, so observers see either the old file or the complete new one, never a partial.
- Why does deleting a non-empty directory fail, and how do you delete a whole tree?Files.delete only removes a single empty entry, so a non-empty directory throws DirectoryNotEmptyException. Delete the tree by walking it depth-first (e.g. Files.walk(...) sorted in reverse, or walkFileTree) and deleting each file before its parent directory.
saying these in an interview costs you the question
- Assuming Files.copy on a directory copies contents recursively
- Expecting ATOMIC_MOVE to work across different disks/partitions
- Calling delete on a non-empty directory and expecting it to clear it
- Confusing createDirectory (one level, parent required) with createDirectories