The Files.move(source, target) method is how we rename or move a file in Java, and it renames the file when the target is in the same directory and moves it when the target is in another directory. The same method renames and moves directories, and it throws FileAlreadyExistsException instead of overwriting an existing target.
We rename files to add a date or a version to them, such as rotating app.log to app.log.1. We move files to pass them between the steps of a pipeline, for example from an incoming folder to a processed folder once an import job has read them.
The following example renames an order file in place and moves it afterwards into a processed folder.
Path dir = Files.createTempDirectory("orders");
Path order = Files.writeString(dir.resolve("order.csv"), "id,qty");
Path renamed = Files.move(order, order.resolveSibling("order-1.csv"));
String newName = renamed.getFileName().toString(); // "order-1.csv"
Path processed = Files.createDirectories(dir.resolve("processed"));
Path moved = Files.move(renamed, processed.resolve(renamed.getFileName()));
boolean oldGone = Files.notExists(renamed); // true
String content = Files.readString(moved); // "id,qty"
The call resolveSibling() builds the new name in the same folder, while resolve() on the target folder keeps the old name. We look at replacing a target, atomic moves for files that other programs watch, moves between disks, renaming directories, the older File.renameTo(), and the helpers in Guava and Commons IO.
1. Renaming and Moving with Files.move()
The method Files.move(Path, Path, CopyOption…) takes the current path and the complete new path of the file. On the same file system, the operating system changes only the directory entry, so even a large file is renamed or moved at once without copying its bytes. The method returns the target path.

The default rules are strict, so a move never destroys data by accident.
- If the target exists, the method throws FileAlreadyExistsException.
- If the parent folder of the target does not exist, it throws NoSuchFileException.
- If the source and target are the same file, the method does nothing.
- If the source is a symbolic link, the link itself is moved, not the file it points to.
- The last-modified time is kept, even when the move has to copy the file.
Path inbox = Files.createTempDirectory("inbox");
Path invoice = Files.writeString(inbox.resolve("invoice.txt"), "Total 50");
Path taken = Files.writeString(inbox.resolve("invoice-old.txt"), "Total 10");
Path clash = Files.move(invoice, taken); // FileAlreadyExistsException
Path noFolder = Files.move(invoice, inbox.resolve("2026/invoice.txt")); // NoSuchFileException
To move a file into a folder that may not exist yet, we call Files.createDirectories() on the folder first. It does nothing when the folder exists, so the call is safe on every run.
1.1. Replacing an Existing Target
Log rotation renames app.log.1 to app.log.2 even when an older app.log.2 is still there. Passing StandardCopyOption.REPLACE_EXISTING deletes the existing target and moves the source in its place. A non-empty directory is never replaced, and the move throws DirectoryNotEmptyException instead.
Path logs = Files.createTempDirectory("logs");
Path current = Files.writeString(logs.resolve("app.log.1"), "today");
Path older = Files.writeString(logs.resolve("app.log.2"), "last week");
Files.move(current, older, StandardCopyOption.REPLACE_EXISTING);
String rotated = Files.readString(older); // "today"
boolean freed = Files.notExists(current); // true
2. Atomic Moves with StandardCopyOption.ATOMIC_MOVE
An atomic move happens in one step from the point of view of every other program. A reader sees either the old state or the new one, never a half-moved or half-written file. The option ATOMIC_MOVE asks for that guarantee, and Files.move() throws AtomicMoveNotSupportedException when the file system cannot give it, for example when the target is on another disk.
With ATOMIC_MOVE, all other options are ignored, so adding REPLACE_EXISTING next to it changes nothing. Whether an existing target is replaced depends on the platform. On Linux and macOS the rename replaces it, and the JDK on Windows replaces it as well, so ATOMIC_MOVE is the wrong tool for code that must never overwrite an existing target.
A reporting service writes sales.csv into a folder that another service watches with a WatchService. If the writer creates the file in place, the watcher can open it after the first few kilobytes. Writing to a temporary file in the same folder and moving it with ATOMIC_MOVE means the watcher only ever sees the complete file.
Path shared = Files.createTempDirectory("shared");
Path temp = Files.createTempFile(shared, "sales-", ".tmp");
Files.writeString(temp, "region,total\nnorth,420");
Path published = Files.move(temp, shared.resolve("sales.csv"), StandardCopyOption.ATOMIC_MOVE);
String report = Files.readString(published); // "region,total\nnorth,420"
When the code must also run on file systems without atomic renames, such as some network shares, we try the atomic move first and fall back to a plain move.
static Path moveSafely(Path source, Path target) throws IOException {
try {
return Files.move(source, target, StandardCopyOption.ATOMIC_MOVE);
} catch (AtomicMoveNotSupportedException e) {
return Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
}
}
3. Moving Files Across File Systems
A rename works only inside one file store, which is one disk partition, one mounted volume or one network share. When the target is on another file store, such as from /tmp to a mounted backup drive, or from C: to D:, Files.move() behaves differently for files and directories.
| Source | Same file store | Different file store |
|---|---|---|
| File | Renamed in one step | Copied to the target, and the source is deleted |
| Empty directory | Renamed | Created at the target, and the source is deleted |
| Non-empty directory | Renamed with all entries | Throws DirectoryNotEmptyException |
| Any, with ATOMIC_MOVE | Renamed atomically | Throws AtomicMoveNotSupportedException |
The copy-and-delete fallback for files is not atomic. If the process stops in the middle, both the source and a partial target can exist. We can check in advance whether two paths share a file store, because Files.getFileStore() returns equal objects for paths on the same store.
Path uploads = Files.createTempDirectory("uploads");
Path archive = Files.createTempDirectory("archive");
boolean sameStore = Files.getFileStore(uploads).equals(Files.getFileStore(archive)); // true
For a whole folder that may cross file stores, the portable approach is a move that falls back to a recursive copy followed by a recursive delete. The copy a directory and delete a directory articles have both walks.
4. Renaming or Moving a Directory
Renaming a folder on the same file store takes one Files.move() call, and every file inside keeps its place relative to the folder. A photo app that renames an album from trip to paris-2026 needs only that call, however many photos the album holds.
Path albums = Files.createTempDirectory("albums");
Path trip = Files.createDirectories(albums.resolve("trip"));
Files.writeString(trip.resolve("day1.jpg"), "jpg");
Path paris = Files.move(trip, trip.resolveSibling("paris-2026"));
boolean photoMoved = Files.exists(paris.resolve("day1.jpg")); // true
Path parent = Files.createDirectories(albums.resolve("europe"));
Path nested = Files.move(paris, parent.resolve(paris.getFileName()));
boolean stillThere = Files.exists(nested.resolve("day1.jpg")); // true
The rules from section 1 apply to folders too. An existing target folder causes FileAlreadyExistsException, and a move into a folder on another disk throws DirectoryNotEmptyException when the source has entries.
5. Using File.renameTo()
Code written before java.nio.file renames with File.renameTo(File). It returns true or false and never says why a rename failed, so a missing source, a missing folder and a locked file all look the same.
File folder = Files.createTempDirectory("legacy").toFile();
File draft = new File(folder, "draft.txt");
boolean created = draft.createNewFile(); // true
boolean renamedOk = draft.renameTo(new File(folder, "final.txt")); // true
boolean missing = new File(folder, "nope.txt").renameTo(new File(folder, "x.txt")); // false
The behavior of renameTo() also depends on the platform. On Linux, it replaces an existing target without any warning, while on Windows the same call returns false, and a move to another disk fails on many systems. When old code hands us a File, we convert it with toPath() and use Files.move() to get the same rules and a clear exception everywhere.
File folder = Files.createTempDirectory("legacy").toFile();
File keep = Files.writeString(new File(folder, "final.txt").toPath(), "v1").toFile();
File other = new File(folder, "other.txt");
boolean made = other.createNewFile(); // true
Path refused = Files.move(keep.toPath(), other.toPath()); // FileAlreadyExistsException
6. Guava and Commons IO Options
Both libraries wrap the JDK methods. They are useful when the project already depends on them, mostly for the folder helpers in Commons IO.
6.1. Guava’s Files.move()
The method com.google.common.io.Files.move(File, File) takes the complete target path, not the target folder or only the new name. It falls back to copy and delete when a rename fails, and it overwrites an existing target file.
File guavaDir = Files.createTempDirectory("guava").toFile();
File menu = Files.writeString(new File(guavaDir, "menu.txt").toPath(), "soup").toFile();
File menuRenamed = new File(guavaDir, "menu-v2.txt");
com.google.common.io.Files.move(menu, menuRenamed);
boolean guavaMoved = menuRenamed.exists() && !menu.exists(); // true
6.2. Commons IO’s FileUtils
The FileUtils class has one method for each kind of move, and the directory methods copy and delete when the target is on another file system.
| Method | What it does |
|---|---|
| moveFile(File src, File dest, CopyOption…) | Moves or renames a file, and throws FileExistsException if the target exists, even with REPLACE_EXISTING |
| moveFileToDirectory(File src, File dir, boolean create) | Moves a file into a folder, creating the folder when create is true |
| moveDirectory(File src, File dest) | Moves or renames a folder with its contents |
| moveDirectoryToDirectory(File src, File dir, boolean create) | Moves a folder into another folder |
| moveToDirectory(File src, File dir, boolean create) | Moves a file or a folder into a folder |
File base = Files.createTempDirectory("commons").toFile();
File photo = Files.writeString(new File(base, "photo.jpg").toPath(), "jpg").toFile();
FileUtils.moveFileToDirectory(photo, new File(base, "gallery"), true);
boolean inGallery = new File(base, "gallery/photo.jpg").exists(); // true
7. Rename or Move a File in Java FAQs
Extensions, atomicity, a failed atomic move, a false from renameTo() and timestamps are the details these answers cover.
7.1. How do we rename a file without changing its folder?
We build the new path with resolveSibling(), which replaces only the last name element, and pass it to Files.move().
Path photoFile = Files.writeString(Files.createTempFile("img", ".jpeg"), "jpg");
String base = photoFile.getFileName().toString().replaceFirst("\\.jpeg$", "");
Path withJpg = Files.move(photoFile, photoFile.resolveSibling(base + ".jpg"));
boolean jpg = withJpg.toString().endsWith(".jpg"); // true
The same call changes a file extension, since an extension is only part of the file name.
7.2. Is Files.move() atomic?
Only with ATOMIC_MOVE. Without it, a move on one file store is a single rename in practice, but the existence check and the move are not guaranteed to be atomic, and a move across file stores is a copy and a delete. section 2 shows the temporary-file pattern.
7.3. Why does Files.move() throw AtomicMoveNotSupportedException?
The target is on a different file store, or on a file system that cannot rename atomically. We either move the temporary file into the target’s own folder first, or fall back to a plain move as in moveSafely().
7.4. Why does File.renameTo() return false?
The source may not exist, the target folder may be missing, the target may already exist on Windows, the file may be open in another program, or the target may be on another disk. The method cannot tell us which, so Files.move(file.toPath(), target.toPath()) is the way to get the real exception.
7.5. Does moving a file keep its timestamps?
Yes for the last-modified time, which Files.move() copies even when it has to copy the file to another disk, as long as both file stores support it. A rename on the same file store keeps all attributes, because the file itself does not change.
8. Conclusion
The Files.move() method covers renaming and moving for files and folders. It refuses to overwrite unless we pass REPLACE_EXISTING, it renames in one step on the same file store, and it falls back to copy and delete for files on another store, while a non-empty folder on another store needs a recursive copy.
For files that other programs read or watch, a temporary file plus ATOMIC_MOVE publishes the complete file in one step. The older File.renameTo() does not report the reason for a failure and behaves differently per platform, and the Java IO tutorial lists the other file operations that build on Files.
9. References
- Files.move() Javadoc (Java 25)
- StandardCopyOption Javadoc
- File.renameTo() Javadoc
- Dev.java, Manipulating Files and Directories
- Commons IO FileUtils Javadoc
Happy Learning !!