1. おさらい: File vs Path vs Files
昔ながらの File
そう…Java プロジェクトにはレガシーコードがたくさんあります。だからこそ、Java の古参クラス File をもう一度振り返りましょう。これは初期バージョンから存在し、ファイルやフォルダの操作ができます。ファイルが存在するか、名前、サイズ、変更日時の取得、ファイルやフォルダの作成・削除などです。ご存じのとおり欠点も多く、一部のメソッドは直感的ではなく、すべての操作がクロスプラットフォームでサポートされているわけでもありません。さらに、いくつかのメソッドは例外ではなく単に false を返すだけで(デバッグには必ずしも便利ではありません)。
import java.io.File;
File file = new File("example.txt");
System.out.println("ファイルは存在しますか? " + file.exists());
System.out.println("これはファイルですか? " + file.isFile());
System.out.println("これはディレクトリですか? " + file.isDirectory());
Path と Files: 現代的なアプローチ(Java 7+)
Java 7 でパッケージ java.nio.file が導入され、より強力で柔軟なツールが提供されました。主役は 2 つ:
- Path — ファイルやフォルダへのパスを表すインターフェイス。いわば「賢い文字列」で、パスの分解・結合・解析・比較ができます。
- Files — ファイルやディレクトリを扱うための多数の静的メソッドを持つユーティリティクラス。作成、削除、コピー、読み取り、書き込み、情報取得など。
import java.nio.file.Path;
import java.nio.file.Paths;
Path path = Paths.get("example.txt");
System.out.println("パス: " + path);
豆知識: クラス Path は単なる文字列ではありません!ディレクトリの区切り文字を理解し、相対パス・絶対パスを解析でき、Windows と Linux の両方で同様に動作します。
File と Path/Files の比較表
| 基準 | File(旧 API) | Path + Files(新しい API) |
|---|---|---|
| 構文 | OOP スタイル | Path + Files の静的メソッドの組み合わせ |
| クロスプラットフォーム性 | 部分的 | 優秀(OS を考慮) |
| 例外 | 常ではない | ほぼ常に |
| 新機能 | なし | あり(属性、権限、リンク等) |
| 推奨 | あまり推奨しない | 推奨 |
2. ファイル/ディレクトリ情報の取得
ファイルやフォルダについて、存在、種類(ファイルかディレクトリ)、サイズ、名前、パス、親ディレクトリといった重要事項を確認する方法を見ていきます。
存在確認
File を使う場合
File file = new File("example.txt");
if (file.exists()) {
System.out.println("ファイルは存在します!");
} else {
System.out.println("ファイルが見つかりません。");
}
Path と Files を使う場合
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Path path = Paths.get("example.txt");
if (Files.exists(path)) {
System.out.println("ファイルは存在します!");
} else {
System.out.println("ファイルが見つかりません。");
}
アドバイス: 新規プロジェクトでは常に Path と Files を使いましょう。安全で、使いやすく、クロスプラットフォームです。
種類の判定: ファイルかディレクトリか
File
if (file.isFile()) {
System.out.println("これはファイルです。");
} else if (file.isDirectory()) {
System.out.println("これはディレクトリです。");
}
Path + Files
if (Files.isRegularFile(path)) {
System.out.println("これはファイルです。");
} else if (Files.isDirectory(path)) {
System.out.println("これはディレクトリです。");
}
ファイルサイズの取得
File
long size = file.length();
System.out.println("ファイルサイズ: " + size + " バイト");
Path + Files
try {
long size = Files.size(path);
System.out.println("ファイルサイズ: " + size + " バイト");
} catch (IOException e) {
System.out.println("ファイルサイズ取得中のエラー: " + e.getMessage());
}
注意: フォルダに対しては length() は常に 0 を返し、Files.size(path) は IOException をスローします。フォルダのサイズは中のすべてのファイルの合計です(詳細は今後の講義で扱います)。
絶対パスと相対パスの取得
File
System.out.println("相対パス: " + file.getPath());
System.out.println("絶対パス: " + file.getAbsolutePath());
Path
System.out.println("相対パス: " + path);
System.out.println("絶対パス: " + path.toAbsolutePath());
ファイル名と親ディレクトリの取得
File
System.out.println("ファイル名: " + file.getName());
System.out.println("親ディレクトリ: " + file.getParent());
Path
System.out.println("ファイル名: " + path.getFileName());
System.out.println("親ディレクトリ: " + path.getParent());
ヒント: Path はファイルだけでなくフォルダ、相対・絶対パスにも対応し、パスを簡単に要素へ分解できます。
3. ファイル属性の取得
サイズや名前だけでなく、作成日時、最終更新日時、アクセス権など、より興味深い情報を知りたいこともあります。
作成日時と最終更新日時
File(制限あり)
long lastModified = file.lastModified();
System.out.println("最終更新日時: " + new java.util.Date(lastModified));
欠点: File ではファイルの作成日時を取得できません!
Path + Files
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
try {
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
FileTime creationTime = attrs.creationTime();
FileTime lastModifiedTime = attrs.lastModifiedTime();
System.out.println("作成日時: " + creationTime);
System.out.println("最終更新日時: " + lastModifiedTime);
} catch (IOException e) {
System.out.println("属性取得中のエラー: " + e.getMessage());
}
アクセス権の確認
File
System.out.println("読み取り可能? " + file.canRead());
System.out.println("書き込み可能? " + file.canWrite());
System.out.println("実行可能? " + file.canExecute());
Path + Files
System.out.println("読み取り可能? " + Files.isReadable(path));
System.out.println("書き込み可能? " + Files.isWritable(path));
System.out.println("実行可能? " + Files.isExecutable(path));
豆知識: Windows ではアクセス権の表現が制限されていますが、Unix 系ではより多くの権限を取得・変更できます(たとえば POSIX 属性)。
4. ファイル情報取得でよくあるミス
エラー1: Path が必要なのに File を使う。
多くの初心者は「簡単だから」「ネット上のサンプルがそうしているから」という理由で File を使い続けます。しかし Path と Files を使えば同じことを、より堅牢でモダンに実現できます。
エラー2: オブジェクトの種類判定を File だけで行う。
file.isFile() と file.isDirectory() だけだと、シンボリックリンクやデバイスなどの「特殊ファイル」を見落とす可能性があります。現代的な API には Files.isRegularFile(path)、Files.isDirectory(path) などの判定があります。
エラー3: 例外を無視する。
メソッド Files.size(path) や Files.readAttributes(...) は IOException をスローします。例外を処理しないと、アクセスエラーや実行中にファイルが消えた場合にプログラムが落ちてしまいます。
エラー4: フォルダのサイズを直接取得できると期待する。
メソッド Files.size(path) はフォルダに対しては例外になります。フォルダのサイズを知るには、中のすべてのファイルのサイズを再帰的に合計する必要があります。
エラー5: アクセス権の確認が不十分。
ファイルが存在しても、読み取りや書き込みの権限がない場合があります。操作の前に必ず権限を確認しましょう: Files.isReadable(path)、Files.isWritable(path)、Files.isExecutable(path)。
GO TO FULL VERSION