Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Java Files.move: atomic publication is a filesystem contract

Last updated: 5 Oct 20264 min read
tutorial
IntermediateBy AITrove Editorial

Files.move with ATOMIC_MOVE requests one filesystem-level move that exposes a finished file at its destination or reports that atomic movement is unsupported.

Stage beside the destination

Write the complete artifact to a temporary file in the destination directory, then close it before the move. Keeping source and destination on the same file store improves the chance that an atomic move is supported. The program publishes a new unique manifest path and refuses to silently copy when ATOMIC_MOVE is unavailable.

The Java API leaves replacement of an existing target under ATOMIC_MOVE implementation-specific. Do not use this fixture as an unconditional overwrite recipe. Allocate a unique destination name or decide how to handle an existing target under the specific provider you deploy. Versioned publication is a separate way to avoid ambiguous replacement.

Visibility is not durability

An atomic rename controls what a reader can observe during the name change. It does not promise that bytes or directory metadata survive power loss; a durability requirement needs the relevant file and directory sync procedure for the platform. A non-atomic fallback also has different partial-failure behavior. If the move fails, keep or clean the staged file according to a retry rule rather than pretending the destination was published.

The example reads back the complete UTF-8 manifest only after the move. File ownership and resource cleanup cover the earlier write boundary.

Working program

Java
import java.nio.charset.StandardCharsets;
import java.nio.file.AtomicMoveNotSupportedException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

public class ManifestPublication {
    public static void main(String[] args) throws Exception {
        Path directory = Files.createTempDirectory("aitrove-manifest-");
        Path staged = Files.createTempFile(directory, "staged-", ".txt");
        Path published = directory.resolve("manifest-47.txt");
        try {
            Files.write(staged, "receipt-47=accepted\n".getBytes(StandardCharsets.UTF_8));
            try {
                Files.move(staged, published, StandardCopyOption.ATOMIC_MOVE);
            } catch (AtomicMoveNotSupportedException unsupported) {
                System.out.println("atomic move unavailable");
                return;
            }
            String manifest = new String(Files.readAllBytes(published), StandardCharsets.UTF_8);
            System.out.println(manifest.trim());
        } finally {
            Files.deleteIfExists(staged);
            Files.deleteIfExists(published);
            Files.delete(directory);
        }
    }
}

Cost and ownership

Writing and verifying an artifact of n bytes costs O(n) time and O(n) memory in this small fixture because readAllBytes loads it for checking. A streaming verifier can avoid that full read. The move cost and durability depend on the filesystem provider; no portable constant-time or crash-survival promise follows from the Java call alone.

Common Mistakes

  • Do not silently retry without ATOMIC_MOVE and still claim atomic publication.
  • Do not assume atomic replacement of an existing target is portable.
  • Do not equate atomic visibility with durable storage after a power failure.

Read next

Java file I/O: UTF-8, streaming reads, and path ownership, Java file channels: buffer positions and partial transfers, Java versioned data changes: checksums and a committed ledger, Java try-with-resources: close order and suppressed failures.

Continue with: Java WatchService: register, consume, and reset each key, Java WatchService OVERFLOW: reconcile against directory state.

Continue with: Java FileChannel.force: distinguish written bytes from forced storage, Java FileChannel.transferTo: verify the byte count on every pass, Java FileChannel.truncate: cut only after validating the recovery offset.

Continue with: Java XML Transformer: bound serialized output and external access, Java ZipOutputStream: close each entry and the archive before publication.

java
atomic-file-publication
Storage details