1. 概要

この記事では、Javaでファイルをコピーする一般的な方法について説明します。

まず、標準のIONIO.2 API、および2つの外部ライブラリcommons-ioguavaを使用します。

2. IO API(JDK7より前)

まず、からにjava.ioAPIを使用してファイルをコピーします。ストリームを開き、コンテンツをループして別のストリームに書き出す必要があります:

@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())));
}

このような基本的な機能を実装するには、かなりの作業が必要です。

幸いなことに、 JavaはコアAPIを改善し、NIO.2APIを使用してファイルをコピーする簡単な方法があります。

3. NIO.2 API(JDK7)

NIO.2 を使用すると、 NIO.2 が下位レベルのシステムエントリポイントを使用するため、ファイルコピーのパフォーマンスを大幅に向上させることができます。

Files。copy()メソッドがどのように機能するかを詳しく見てみましょう。

copy()メソッドを使用すると、コピーオプションを表すオプションの引数を指定できます。 デフォルトでは、ファイルとディレクトリをコピーしても既存のものは上書きされず、ファイル属性もコピーされません。

この動作は、次のコピーオプションを使用して変更できます。

  • REPLACE_EXISTING –ファイルが存在する場合はファイルを置き換えます
  • COPY_ATTRIBUTES –メタデータを新しいファイルにコピーします
  • NOFOLLOW_LINKS –シンボリックリンクをたどるべきではありません

NIO.2ファイルクラスは、ファイルシステム内のファイルとディレクトリをコピーするためのオーバーロードされた copy()メソッドのセットを提供します。

copy()と2つのPath引数を使用した例を見てみましょう。

@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)));
}

ディレクトリのコピーは浅いであることに注意してください。つまり、ディレクトリ内のファイルとサブディレクトリはコピーされません。

4. Apache Commons IO

Javaでファイルをコピーするもう1つの一般的な方法は、commons-ioライブラリを使用することです。

まず、依存関係を追加する必要があります。

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

最新バージョンは、 MavenCentralからダウンロードできます。

次に、ファイルをコピーするには、 FileUtilsクラスで定義されたcopyFile()メソッド。 このメソッドは、ソースファイルとターゲットファイルを受け取ります。

copyFile()メソッドを使用したJUnitテストを見てみましょう。

@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. グアバ

最後に、GoogleのGuavaライブラリを見ていきます。

繰り返しますが、Guava を使用する場合は、依存関係を含める必要があります。

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

最新バージョンは、MavenCentralにあります。

そして、ファイルをコピーするGuavaの方法は次のとおりです。

@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. 結論

この記事では、Javaでファイルをコピーする最も一般的な方法について説明しました。

この記事の完全な実装は、Githubのにあります。