1. ディレクトリの作成
ディレクトリ(フォルダとも呼ばれます)は単なるファイルの入れ物ではなく、ディスク上のデータ整理の基盤です。アプリケーションでは入出力データ、ログ、一時ファイルなどのために、常にディレクトリを作成します。現代的な API の java.nio.file を使えば、簡潔かつクロスプラットフォームに扱えます。
ここでは、Files、Path、Paths クラスを使って、ディレクトリの作成・削除・内容の一覧取得を見ていきます。
Files.createDirectory(path)
指定したパスに 1 つ のディレクトリを作成します。親ディレクトリが存在しない場合は、例外が送出されます。
import java.nio.file.*;
public class DirectoryDemo {
public static void main(String[] args) throws Exception {
Path dir = Paths.get("testDir");
if (!Files.exists(dir)) {
Files.createDirectory(dir);
System.out.println("ディレクトリを作成しました: " + dir.toAbsolutePath());
} else {
System.out.println("ディレクトリは既に存在します: " + dir.toAbsolutePath());
}
}
}
既に存在するディレクトリを作成しようとすると、FileAlreadyExistsException が発生します。
Files.createDirectories(path)
ディレクトリの階層全体を作成します。途中のディレクトリが存在しない場合は自動的に作成されます。チェーンの一部が既に存在していてもエラーにはなりません。
Path nestedDir = Paths.get("parent/child/grandchild");
Files.createDirectories(nestedDir);
System.out.println("ディレクトリ階層を作成しました: " + nestedDir.toAbsolutePath());
例えるなら、家だけでなく、まだ存在しないなら玄関や通りまでまとめて Java に作らせるイメージです。
よくある例:プロジェクト用の構成を作る
たとえば、レポートをフォルダ output/reports/2024 に保存したいとします。各ディレクトリを手作業で確認するのではなく、createDirectories を使いましょう。
Path reportsPath = Paths.get("output/reports/2024");
Files.createDirectories(reportsPath);
何が既にあり、何を作る必要があるかは Java が判断してくれます。
2. ファイルとディレクトリの削除
Files.delete(path)
ファイルまたは 空の ディレクトリを削除します。ディレクトリが空でない場合は、DirectoryNotEmptyException が送出されます。
Path dir = Paths.get("testDir");
try {
Files.delete(dir);
System.out.println("ディレクトリを削除しました: " + dir.toAbsolutePath());
} catch (DirectoryNotEmptyException e) {
System.out.println("削除できません: ディレクトリが空ではありません!");
}
Files.deleteIfExists(path)
delete と同様に動作しますが、対象が存在しない場合はエラーを投げません。何かを削除できた場合は true、対象がなかった場合は false を返します。
Path file = Paths.get("output/reports/2024/report.txt");
if (Files.deleteIfExists(file)) {
System.out.println("ファイルを削除しました。");
} else {
System.out.println("ファイルが見つかりません。何も削除していません。");
}
空でないディレクトリを削除するには?
空でないディレクトリはそのままでは削除できません。まず中身(ファイルとサブディレクトリ)をすべて削除し、その後でディレクトリ本体を削除します。これは再帰的に処理します。例えば、Files.walkFileTree を使います:
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
public class DeleteDirectoryRecursively {
public static void main(String[] args) throws IOException {
Path dir = Paths.get("parent");
if (Files.exists(dir)) {
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
System.out.println("ディレクトリとその中身をすべて削除しました。");
}
}
}
始めたばかりの方は、このコードに怖気づく必要はありません — 後ほど walkFileTree を詳しく解説します。
3. ディレクトリ内容の一覧表示
Files.list(path)
Stream<Path>(パスのストリーム)を返します。Stream API でディレクトリの内容を処理できます。各要素はファイルまたはサブディレクトリです(再帰ではありません!)。
Path dir = Paths.get("output/reports");
if (Files.exists(dir) && Files.isDirectory(dir)) {
try (var stream = Files.list(dir)) {
stream.forEach(path -> System.out.println(path.getFileName()));
}
}
重要なポイント: ストリームは必ずクローズする必要があるため、try‑with‑resources を使用します。
例: ファイル名とサブディレクトリ名を出力する
Path reports2024 = Paths.get("output/reports/2024");
try (var stream = Files.list(reports2024)) {
stream.forEach(path -> {
String type = Files.isDirectory(path) ? "ディレクトリ" : "ファイル";
System.out.println(path.getFileName() + " — " + type);
});
}
コレクションとしてファイル一覧を取得する
List<Path> files = Files.list(reports2024)
.filter(Files::isRegularFile)
.toList();
System.out.println("ディレクトリ内のファイル:");
files.forEach(System.out::println);
重要: Files.list(path) は現在のディレクトリ(最上位)の内容だけを返します。再帰的に走査する場合は Files.walk(path) を使用してください。
4. 実践: ミニファイルマネージャー
ユーティリティはディレクトリ mydata/logs とファイル log1.txt を作成し、フォルダの内容を表示してから、すべてを削除します。
import java.nio.file.*;
import java.io.IOException;
public class MiniFileManager {
public static void main(String[] args) throws IOException {
Path logsDir = Paths.get("mydata/logs");
Files.createDirectories(logsDir);
Path logFile = logsDir.resolve("log1.txt");
Files.writeString(logFile, "こんにちは、ログ!");
System.out.println("ディレクトリ " + logsDir + " の内容:");
try (var stream = Files.list(logsDir)) {
stream.forEach(path -> System.out.println(" - " + path.getFileName()));
}
Files.deleteIfExists(logFile);
Files.deleteIfExists(logsDir);
System.out.println("ファイルとディレクトリを削除しました。");
}
}
コードに関する補足:
- Files.createDirectories は階層全体の作成を保証します。
- resolve — パスにファイル名を付け足す便利な方法です。
- Files.list のストリームは try‑with‑resources でクローズします — 特に Windows では重要です。
5. 注意点とコツ
存在確認
作成や削除の前に、そのパスが存在するかを確認しておくと便利です:
if (!Files.exists(path)) {
Files.createDirectory(path);
}
アクセス権
プログラムに作成/削除の権限がない場合は AccessDeniedException になります。例えば、一般ユーザーがディスクのルートにフォルダを作成しようとすると、たいていは失敗します。
空のディレクトリ/空でないディレクトリ
削除できるのは空のディレクトリ(Files.delete)だけです。中身ごと削除するには、再帰的な走査(walkFileTree)を使用します。
クロスプラットフォーム性
API java.nio.file は主要な OS で正しく動作し、パス区切り文字も考慮されます。パスの構築には、文字列を連結するのではなく、Paths.get と Path.resolve を使いましょう。
シンボリックリンク
基本的な用途では気にしなくても構いませんが、通常のファイルでもディレクトリでもない「変わった」エントリに出会ったら、それはシンボリックリンクかもしれません。高度な講義で改めて取り上げます。
6. ディレクトリ操作でよくあるミス
ミス 1: 空でないディレクトリを単純に Files.delete(path) で削除しようとする。 Java は DirectoryNotEmptyException を投げます。まず中身を削除してから本体を削除します。
ミス 2: Files.list() のストリームを閉じ忘れる。 try‑with‑resources を使わないとストリームが開いたままになり、Windows ではフォルダ削除時にエラーになる可能性があります。
ミス 3: 親ディレクトリの存在確認をせずに作成する。 Files.createDirectory を parent/child のようなパスに対して呼び出し、parent が存在しないと、NoSuchFileException になります。Files.createDirectories を使用しましょう。
ミス 4: 不要なのに絶対パスを使う。 プロジェクト内では相対パスを優先しましょう — その方がコードは移植しやすくなります。
ミス 5: IOException を処理しない。 どのファイルシステム操作も失敗し得ます。try-catch で包むか、上位にスローしてください。
ミス 6: 権限のない場所で作成/削除しようとする。 この場合は AccessDeniedException になります。実行コンテキストとアクセス権を確認してください。
GO TO FULL VERSION