CodeGym /コース /JAVA 25 SELF /ファイルとディレクトリのコピーと移動

ファイルとディレクトリのコピーと移動

JAVA 25 SELF
レベル 40, レッスン 1
使用可能

1. ファイルのコピー

メソッド Files.copy: 基本構文

Java では、ファイルやディレクトリのコピーに Files.copy(java.nio.file)という静的メソッドを使います。すでに一度登場していますが、ここでは詳しく見ていきます。Files.copy の基本構文は次のとおりです。

Files.copy(Path source, Path target, CopyOption... options)
  • source — 元のファイルまたはディレクトリへのパス。
  • target — コピー先のパス。
  • options — 追加オプション(例: 上書きを許可)。

最も簡単な例

カレントディレクトリのファイル "input.txt" を、フォルダ "backup" の "input_backup.txt" という名前でコピーしてみましょう。

import java.nio.file.*;

public class CopyExample {
    public static void main(String[] args) throws Exception {
        Path source = Path.of("input.txt");
        Path target = Path.of("backup/input_backup.txt");

        Files.copy(source, target);
        System.out.println("ファイルをコピーしました!");
    }
}

重要なポイント:

  • 宛先ファイルがすでに存在する場合、FileAlreadyExistsException が送出されます。
  • "backup" ディレクトリが存在しない場合はエラーになります — ディレクトリは事前に作成しておく必要があります!

上書きしてコピー

ファイルの上書きを許可するには、StandardCopyOption.REPLACE_EXISTING を指定します。

Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);

表: 主なコピーオプション

オプション 説明
StandardCopyOption.REPLACE_EXISTING
既存のファイルがある場合は上書きする
StandardCopyOption.COPY_ATTRIBUTES
属性(作成日時など)もコピーする
StandardCopyOption.ATOMIC_MOVE
アトミックな移動(move と一緒のときのみ有効)

ファイルを別ディレクトリにコピー

コピー前に、宛先ディレクトリが存在することを確認してください。

Path targetDir = Path.of("backup");
if (!Files.exists(targetDir)) {
    Files.createDirectory(targetDir);
}
Files.copy(source, targetDir.resolve("input_backup.txt"), StandardCopyOption.REPLACE_EXISTING);

ディレクトリのコピー: 注意点

Files.copy は、ディレクトリを「空の殻」としてしかコピーできません — 中身(ファイルやサブディレクトリ)はコピーされません! ファイルが入ったディレクトリをコピーしようとしても、空のディレクトリしかできません。中身ごとディレクトリをコピーするには、再帰的に走査して各ファイルを個別にコピーする必要があります(この点は後続の講義で扱います)。

例: あるディレクトリから別のディレクトリへファイルをコピー

Path source = Path.of("data/report.txt");
Path target = Path.of("backup/report.txt");

Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);

コピー時のエラー処理

コピーは様々な理由で失敗することがあります。アクセス不可、ファイルの占有、空き容量不足、既存ファイルの存在など。常に try-catch を使うのがおすすめです。

try {
    Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
    System.out.println("コピーに成功しました!");
} catch (FileAlreadyExistsException e) {
    System.out.println("ファイルはすでに存在します: " + target);
} catch (IOException e) {
    System.out.println("入出力エラー: " + e.getMessage());
}

2. ファイルとディレクトリの移動

メソッド Files.move: 構文

ファイルやディレクトリの移動は次のメソッドで行います。

Files.move(Path source, Path target, CopyOption... options)

ここで、source は(移動元の)パス、target はファイルやディレクトリを置きたい先のパス、options は追加設定(例: 既存ファイルの置換)です。

なお、移動は単なる「引っ越し」だけでなく、名前変更の手段でもあります(名前だけが変わる場合)。また、宛先に同名のファイルがすでにある場合、REPLACE_EXISTING を指定しなければ例外が送出されます。

例: ファイルを別ディレクトリへ移動

Path source = Path.of("data/report.txt");
Path target = Path.of("archive/report.txt");

Files.move(source, target);
System.out.println("ファイルを移動しました!");

既存ファイルを置き換えて移動

Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);

ディレクトリの移動

Path oldDir = Path.of("data/old_reports");
Path newDir = Path.of("archive/old_reports");

Files.move(oldDir, newDir);

ディレクトリ全体(内部のファイルやサブディレクトリを含む)が新しい場所に移動します。
ただし、宛先に同名のディレクトリがすでにある場合はエラーになります。

異なるファイルシステム間の移動

異なるドライブ間(例: "C:" から "D:")で移動する場合、内部的には「コピーしてから元ファイルを削除」します。操作がアトミックとしてサポートされていない場合、AtomicMoveNotSupportedException が送出されることがあります。

move と copy の違い

  • copy — 元のファイル/ディレクトリはそのまま残り、複製が作られる。
  • move — 元のファイル/ディレクトリは消え、新しい場所にのみ存在する。

3. ファイルとディレクトリの名前変更

Java には「ファイル名を変更する」専用メソッドはありません。名前変更は移動の特殊ケースで、同じディレクトリ内で別の名前のパスを指定します。

例: ファイル名の変更

ファイル "report.txt" を同じディレクトリ内で "report_old.txt" に変更してみます。

Path dir = Path.of("data");
Path oldName = dir.resolve("report.txt");
Path newName = dir.resolve("report_old.txt");

Files.move(oldName, newName);
System.out.println("ファイル名を変更しました!");

重要な注意点

宛先ディレクトリに指定した名前のファイルやディレクトリがすでに存在する場合、メソッドは例外を送出します。この制限を回避して置き換えを許可するには、StandardCopyOption.REPLACE_EXISTING を使用します。

例:

Path source = Paths.get("old_name.txt");
Path target = Paths.get("new_name.txt");

// 既存なら上書きして名前を変更する
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);

この例では、ファイル "old_name.txt" は "new_name.txt" に名前変更されます。ディレクトリ内に同名ファイルがすでにある場合は、それが上書きされます。

ディレクトリ名の変更

Path oldDir = Path.of("data/old_reports");
Path newDir = Path.of("data/archived_reports");

Files.move(oldDir, newDir);
System.out.println("ディレクトリ名を変更しました!");

4. コピー、移動、名前変更時のエラー処理

ファイルシステム操作には予期しない事態のリスクがつきものです。よくある問題は次のとおりです。

ファイルがすでに存在する。
例外: FileAlreadyExistsException。対処: 上書きしたい場合は REPLACE_EXISTING を使う。

ファイルやディレクトリが他のプロセスにより使用中。
例外: IOException。例えば、ファイルが他のプログラムで開かれている。

ファイルまたはディレクトリへのアクセス権がない。
例外: AccessDeniedException。ユーザー権限の問題。

異なるファイルシステム間の移動。
例外: AtomicMoveNotSupportedException。すべてのファイルシステムがアトミックな移動をサポートしているわけではない。

宛先ディレクトリが存在しない。
コピー/移動の前に、宛先ディレクトリが事前に作成されていることを確認してください。

エラー処理の例

try {
    Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
} catch (FileAlreadyExistsException e) {
    System.out.println("宛先ファイルはすでに存在します: " + target);
} catch (AtomicMoveNotSupportedException e) {
    System.out.println("アトミックムーブはサポートされていません: " + e.getMessage());
} catch (IOException e) {
    System.out.println("移動時のエラー: " + e.getMessage());
}

5. 実践的な推奨事項

宛先のファイル/ディレクトリの存在確認

コピーや移動の前に、宛先パスが既に使われていないかを確認すると良いでしょう。

if (Files.exists(target)) {
    System.out.println("ファイルが既にあるため、上書きしません。");
} else {
    Files.copy(source, target);
}

安全のための一時ファイルの活用

重要なファイルの更新のような複雑な操作では、まず一時ファイルにコピーしてから本体を置き換える、という手順がよく使われます。

Path temp = Path.of("data/report.tmp");
Files.copy(source, temp, StandardCopyOption.REPLACE_EXISTING);
Files.move(temp, target, StandardCopyOption.REPLACE_EXISTING);

この方法により、障害発生時のデータ損失リスクを最小化できます。

例: 置換前にバックアップを作成する

Path file = Path.of("data/report.txt");
Path backup = Path.of("data/report_backup.txt");

if (Files.exists(file)) {
    Files.copy(file, backup, StandardCopyOption.REPLACE_EXISTING);
    System.out.println("バックアップを作成しました。");
}

6. 表: 主なメソッドとオプション

操作 Java NIO メソッド 特徴
コピー
Files.copy(source, target, ...)
ディレクトリの中身はコピーされない!
移動
Files.move(source, target, ...)
名前変更にも利用可能
名前変更
Files.move(source, target, ...)
同じディレクトリ内の新しいパス
上書き
StandardCopyOption.REPLACE_EXISTING
宛先のファイル/ディレクトリを上書き
存在確認
Files.exists(path)
ファイル/ディレクトリの存在を確認

7. ファイルのコピー、移動、名前変更での典型的なミス

エラー1: 存在しないディレクトリにファイルをコピーしようとしている。 宛先ディレクトリが作成されていないと、NoSuchFileException になります。対処: Files.createDirectories で事前に作成する。

エラー2: Files.copy でディレクトリ全体をコピーしようとしている。 メソッドは「空の殻」だけを作り、中身はコピーしません。完全なコピーには再帰的な走査が必要です。

エラー3: 既存ファイルの扱いをしていない。 REPLACE_EXISTING を渡さず、すでにファイルがあると例外が送出されます。このケースは明示的に処理しましょう。

エラー4: 新しい名前のファイルが既に存在する状態で名前変更しようとしている。 同様に、FileAlreadyExistsException になります。名前変更の前に存在を確認することができます。

エラー5: 異なるファイルシステム間の移動。 操作が「アトミック」にサポートされず、AtomicMoveNotSupportedException が送出されることがあります。この場合はアトミックでない通常の移動を使ってください。

エラー6: アクセス権不足またはファイルのロック。 ファイルが他のプログラムで開かれている、または読み書き権限がない場合、AccessDeniedException や IOException になります。必ずこれらの例外を処理しましょう。

1
タスク
JAVA 25 SELF, レベル 40, レッスン 1
ロック未解除
最新のレポートをアーカイブに移動 📦
最新のレポートをアーカイブに移動 📦
1
タスク
JAVA 25 SELF, レベル 40, レッスン 1
ロック未解除
古いドキュメントの名前変更 📝
古いドキュメントの名前変更 📝
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION