Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this article, we’ll cover common ways of copying files in Java.

First, we’ll use the standard IO and NIO.2 APIs, and two external libraries: commons-io and guava.

2. IO API (Before JDK7)

First of all, to copy a file with java.io API, we’re required to open a stream, loop through the content and write it out to another stream:

@Test
public void givenIoAPI_whenCopied_thenCopyExistsWithSameContents() 
  throws IOException {
 
    File copied = new File("src/test/resources/copiedWithIo.txt");
    try (
      InputStream in = new BufferedInputStream(
        new FileInputStream(original));
      OutputStream out = new BufferedOutputStream(
        new FileOutputStream(copied))) {
 
        byte[] buffer = new byte[1024];
        int lengthRead;
        while ((lengthRead = in.read(buffer)) > 0) {
            out.write(buffer, 0, lengthRead);
            out.flush();
        }
    }
 
    assertThat(copied).exists();
    assertThat(Files.readAllLines(original.toPath())
      .equals(Files.readAllLines(copied.toPath())));
}

Quite a lot of work to implement such basic functionality.

Luckily for us, Java has improved its core APIs and we have a simpler way of copying files using NIO.2 API.

3. NIO.2 API (JDK7)

Using NIO.2 can significantly increase file copying performance since the NIO.2 utilizes lower-level system entry points.

Let’s take a closer look at how the Files.copy() method works.

The copy() method gives us the ability to specify an optional argument representing a copy option. By default, copying files and directories won’t overwrite existing ones, nor will it copy file attributes.

This behavior can be changed using the following copy options:

  • REPLACE_EXISTING – replace a file if it exists
  • COPY_ATTRIBUTES – copy metadata to the new file
  • NOFOLLOW_LINKS – shouldn’t follow symbolic links

The NIO.2 Files class provides a set of overloaded copy() methods for copying files and directories within the file system.

Let’s take a look at an example using copy() with two Path arguments:

@Test
public void givenNIO2_whenCopied_thenCopyExistsWithSameContents() 
  throws IOException {
 
    Path copied = Paths.get("src/test/resources/copiedWithNio.txt");
    Path originalPath = original.toPath();
    Files.copy(originalPath, copied, StandardCopyOption.REPLACE_EXISTING);
 
    assertThat(copied).exists();
    assertThat(Files.readAllLines(originalPath)
      .equals(Files.readAllLines(copied)));
}

Note that directory copies are shallow, meaning that files and sub-directories within the directory are not copied.

4. Apache Commons IO

Another common way to copy a file with Java is by using the commons-io library.

First, we need to add the dependency:

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.15.1</version>
</dependency>

The latest version can be downloaded from Maven Central.

Then, to copy a file we just need to use the copyFile() method defined in the FileUtils class. The method takes a source and a target file.

Let’s take a look at a JUnit test using the copyFile() method:

@Test
public void givenCommonsIoAPI_whenCopied_thenCopyExistsWithSameContents() 
  throws IOException {
    
    File copied = new File(
      "src/test/resources/copiedWithApacheCommons.txt");
    FileUtils.copyFile(original, copied);
    
    assertThat(copied).exists();
    assertThat(Files.readAllLines(original.toPath())
      .equals(Files.readAllLines(copied.toPath())));
}

5. Guava

Finally, we’ll take a look at Google’s Guava library.

Again, if we want to use Guava, we need to include the dependency:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

The latest version can be found on Maven Central.

And here’s the Guava’s way of copying a file:

@Test
public void givenGuava_whenCopied_thenCopyExistsWithSameContents() 
  throws IOException {
 
    File copied = new File("src/test/resources/copiedWithGuava.txt");
    com.google.common.io.Files.copy(original, copied);
 
    assertThat(copied).exists();
    assertThat(Files.readAllLines(original.toPath())
      .equals(Files.readAllLines(copied.toPath())));
}

6. Conclusion

In this article, we explored the most common ways to copy a file in Java.

The full implementation of this article can be found over on Github.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.