Java
File Handling
Programming
Directory Management
Java IO

Copying files from one directory to another in Java

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Java, copying files from one directory to another is easiest with the java.nio.file API. The basic case is copying one file to a destination path, but real applications often need to create missing directories, overwrite existing files deliberately, and sometimes copy an entire directory tree.

The important distinction is whether you are copying one file or recursively copying many files. Files.copy handles the first case directly, while recursive directory copy needs traversal logic.

Copy a Single File with Files.copy

For most code, Path plus Files.copy is the right starting point.

java
1import java.io.IOException;
2import java.nio.file.Files;
3import java.nio.file.Path;
4import java.nio.file.Paths;
5import java.nio.file.StandardCopyOption;
6
7public class SingleFileCopy {
8    public static void main(String[] args) throws IOException {
9        Path source = Paths.get("/tmp/source/report.txt");
10        Path targetDir = Paths.get("/tmp/archive");
11        Path target = targetDir.resolve(source.getFileName());
12
13        Files.createDirectories(targetDir);
14        Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
15
16        System.out.println("Copied to " + target);
17    }
18}

This example does three important things:

  • builds paths with Path instead of string concatenation
  • creates the destination directory if it does not exist
  • uses REPLACE_EXISTING so the copy behavior is explicit

Without REPLACE_EXISTING, the copy fails when the target file is already present.

Copy Every File in a Directory Tree

If you want to copy one directory into another, you need to walk the source tree and rebuild the same relative structure under the destination.

java
1import java.io.IOException;
2import java.nio.file.Files;
3import java.nio.file.Path;
4import java.nio.file.Paths;
5import java.nio.file.StandardCopyOption;
6
7public class DirectoryCopy {
8    public static void main(String[] args) throws IOException {
9        Path sourceRoot = Paths.get("/tmp/input");
10        Path targetRoot = Paths.get("/tmp/output");
11
12        try (var stream = Files.walk(sourceRoot)) {
13            stream.forEach(source -> {
14                try {
15                    Path relative = sourceRoot.relativize(source);
16                    Path target = targetRoot.resolve(relative);
17
18                    if (Files.isDirectory(source)) {
19                        Files.createDirectories(target);
20                    } else {
21                        Files.createDirectories(target.getParent());
22                        Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
23                    }
24                } catch (IOException ex) {
25                    throw new RuntimeException(ex);
26                }
27            });
28        }
29    }
30}

The key step is relativize. It preserves the structure of nested folders instead of flattening every file into one destination directory.

When the Old Stream-Based Approach Still Matters

Before java.nio.file, developers copied files with InputStream and OutputStream. That still works, but it is more verbose and easier to get wrong.

java
1import java.io.FileInputStream;
2import java.io.FileOutputStream;
3import java.io.IOException;
4
5public class StreamCopy {
6    public static void main(String[] args) throws IOException {
7        try (FileInputStream in = new FileInputStream("/tmp/source/data.bin");
8             FileOutputStream out = new FileOutputStream("/tmp/target/data.bin")) {
9            byte[] buffer = new byte[8192];
10            int read;
11            while ((read = in.read(buffer)) != -1) {
12                out.write(buffer, 0, read);
13            }
14        }
15    }
16}

Use this only when you have a specific reason to work at the stream level. For ordinary filesystem copies, Files.copy is clearer.

Preserve Metadata Only When You Need It

Copying file content is not the same as copying timestamps, permissions, or ownership. If metadata matters, add the appropriate copy options and test on the actual target platform.

For many application-level tasks, content plus filename is enough. For backup or deployment tooling, metadata may matter a lot.

Common Pitfalls

  • Trying to copy into a directory that does not exist. Create the destination directories first.
  • Copying a whole tree without preserving relative paths, which flattens filenames and causes collisions.
  • Forgetting REPLACE_EXISTING and then treating a file-already-exists failure like a random I/O issue.
  • Using manual stream code when Files.copy would be shorter, safer, and easier to maintain.
  • Assuming file metadata is preserved automatically when only file bytes were copied.

Summary

  • Use Path and Files.copy for most Java file-copy tasks.
  • Create missing destination directories explicitly.
  • Use Files.walk plus relativize to copy directory trees correctly.
  • Prefer java.nio.file over old stream-based code unless you need low-level control.
  • Decide intentionally whether overwriting and metadata preservation are part of the requirement.

Course illustration
Course illustration

All Rights Reserved.