1. はじめに
静的クラス、例えば File や Directory はまるで万能のスイスアーミーナイフのように、いつでも手元にあって素早く目的を達成しますが、特定のオブジェクトに紐づいているわけではありません。一方で FileInfo と DirectoryInfo は特定のファイルやフォルダのために作られたパーソナライズされたツールで、対象について多くを「知って」いて、特に同じオブジェクトに対して繰り返し操作する場合に便利で柔軟です。
インスタンスクラス は特定のファイルシステムオブジェクトの詳細を保持しており、プロパティを最初に取得した後は(オブジェクトが古くなっていない限り)再度ファイルシステムへ問い合わせる必要がないことが多いです。
- FileInfo — 特定のファイルを扱うため。
- DirectoryInfo — 特定のディレクトリ(フォルダ)を扱うため。
これらはサイズ、作成日、拡張子、属性などの詳細情報を取得したり、ファイル/フォルダのコピー、削除、移動などの操作を行うためのプロパティやメソッドを持っています。
FileInfo と DirectoryInfo の構造
両クラスは共通の抽象クラス FileSystemInfo を継承しているので、ファイルとフォルダをまとめて扱うコードが書けます。
System.Object
|
System.MarshalByRefObject
|
System.IO.FileSystemInfo (抽象クラス)
| |
FileInfo DirectoryInfo
いつインスタンスクラスを使うべきか
- 1つのファイル/フォルダについて多くの情報が必要で、それらを何度も使う場合(サイズ、更新日、拡張子、属性など)。
- ディレクトリ内の全ファイル/フォルダを列挙して、それぞれを「生きた」インスタンスとして扱いたい場合。
- ファイルシステムへの不要なアクセスを避けたいとき(キャッシュによる最適化)。
- オブジェクト指向的にコードを書きたいとき(バックアップ、メディアライブラリ、ファイルマネージャー等)。
FileInfo または DirectoryInfo の作り方
using System.IO;
// 既存(または存在しない可能性のある)ファイル用の FileInfo オブジェクトを作る:
var fileInfo = new FileInfo("notes.txt");
// フォルダ用の DirectoryInfo を作る:
var dirInfo = new DirectoryInfo(@"C:\Projects");
// 相対パスや絶対パスはどちらでも使える!
重要なポイント: FileInfo や DirectoryInfo を生成してもファイルやフォルダはファイルシステム上に作られません。これは単なる記述(参照)です。
2. FileInfo の操作
このクラスの主要なプロパティとメソッドを見ていきます。覚え書きはこちら:
| プロパティ/メソッド | 何を返す? | 使用例 |
|---|---|---|
|
ファイル名 | |
|
フルパス | |
|
ファイルサイズ(バイト) | |
|
親ディレクトリ(DirectoryInfo) | |
|
ファイルが実際に存在するか? | |
|
拡張子(.txt など) | |
|
作成日時 | |
|
最終更新日時 | |
|
読み取り専用か? | |
| メソッド | ||
|
ファイルをコピー | |
|
ファイルを削除 | |
|
ファイルを移動 | |
|
読み取り用ストリームを開く | |
|
書き込み用ストリームを開く | |
例: ファイル情報の取得
FileInfo を使ってファイルの詳細情報を取得する小さなモジュールを追加します。
Console.WriteLine("ファイル名を入力してください:");
string fileName = Console.ReadLine();
var file = new FileInfo(fileName);
if (file.Exists)
{
Console.WriteLine($"ファイル名: {file.Name}");
Console.WriteLine($"パス: {file.FullName}");
Console.WriteLine($"サイズ: {file.Length} バイト");
Console.WriteLine($"拡張子: {file.Extension}");
Console.WriteLine($"作成日時: {file.CreationTime}");
Console.WriteLine($"最終更新: {file.LastWriteTime}");
// 補足: 親ディレクトリを表示
Console.WriteLine($"親フォルダ: {file.DirectoryName}");
}
else
{
Console.WriteLine("ファイルが見つかりません。");
}
注意: ここではファイルの中身を読んでいるわけではなく、メタ情報を取得しているだけです。
実践: ファイルのコピーと削除
// ... メインメソッド内でファイル情報表示に成功した後:
Console.WriteLine("コピー先のパスを入力してください:");
string copyPath = Console.ReadLine();
try
{
file.CopyTo(copyPath);
Console.WriteLine($"ファイルは {copyPath} に正常にコピーされました");
}
catch (IOException ex)
{
Console.WriteLine($"ファイルのコピーに失敗しました: {ex.Message}");
}
// 今度はコピーを削除する
Console.WriteLine("コピーを削除しますか? (y/n):");
if (Console.ReadLine().Trim().ToLower() == "y")
{
var copyFile = new FileInfo(copyPath);
if (copyFile.Exists)
{
copyFile.Delete();
Console.WriteLine("コピーを削除しました。");
}
}
3. DirectoryInfo の操作
DirectoryInfo が何を提供してくれるか見てみましょう:
| プロパティ/メソッド | 何を返す? | 使用例 |
|---|---|---|
|
フォルダ名 | |
|
フルパス | |
|
親フォルダ(DirectoryInfo) | |
|
フォルダが存在するか? | |
|
作成日時 | |
|
更新日時 | |
| メソッド | ||
|
フォルダを作成 | |
|
フォルダを削除 | |
|
ファイルの配列(FileInfo の配列) | |
|
サブフォルダの配列(DirectoryInfo の配列) | |
|
ファイルの列挙(IEnumerable<FileInfo> を返す、遅延実行) | |
|
フォルダを移動 | |
例: ファイルとフォルダの列挙
Console.WriteLine("フォルダのパスを入力してください:");
string path = Console.ReadLine();
var dir = new DirectoryInfo(path);
if (!dir.Exists)
{
Console.WriteLine("フォルダが見つかりません!");
return;
}
Console.WriteLine("\n--- ファイル ---");
foreach (var file in dir.GetFiles())
{
Console.WriteLine($"{file.Name} ({file.Length} バイト)");
}
Console.WriteLine("\n--- サブフォルダ ---");
foreach (var subDir in dir.GetDirectories())
{
Console.WriteLine(subDir.Name);
}
4. 便利な注意点
静的メソッドとインスタンスクラスの対比
どちらのアプローチを使うべきか?ワンショットの短い操作、例えば File.Exists(path) や File.ReadAllText(path) のような処理なら、静的メソッドの方がシンプルでオーバーヘッドが少なく高速なことが多いです。
一方で、ファイルやフォルダについてたくさんの情報を得たり、同じオブジェクトに対して繰り返し操作を行ったり、単にOO的にコードを書きたい場合には FileInfo や DirectoryInfo のインスタンスを使う方が良いです。
面白いことに、内部では両方とも似た低レベルのシステム呼び出しを使っています。ただしインスタンスクラスは一部のプロパティ(サイズ、日付、属性など)をキャッシュするので、ファイル数が多い列挙時にはファイルシステムへのアクセス回数を減らしてくれます。
日付と時間まわりの注意
CreationTime、LastWriteTime、LastAccessTime のプロパティは DateTime 型を返します。
Console.WriteLine($"ファイル作成: {file.CreationTime:yyyy-MM-dd HH:mm:ss}");
Console.WriteLine($"最終更新: {file.LastWriteTime:yyyy-MM-dd HH:mm:ss}");
ファイルやフォルダがあなたのインスタンスを作った後にディスク上で変更された場合、キャッシュされた情報が古くなることがあります。情報を更新したいときは file.Refresh() を呼んでください。
実用的なヒント
- インスタンスクラスはファイルシステムのラッパーを作るときに便利: バックアップ、メディアライブラリ、インデクサーなど。
- LINQ と組み合わせると便利: サイズや日付、拡張子でフィルタして選択したオブジェクトに対して操作できます。
- 大量処理では EnumerateFiles() や EnumerateDirectories() の方が GetFiles()/GetDirectories() より優れます。遅延列挙はメモリを節約し、処理開始を速くします。
静的アプローチとインスタンスアプローチの比較
| 静的メソッド | インスタンスクラス | |
|---|---|---|
| 構文 | |
|
| キャッシュ | なし | あり |
| 多くの情報 | 多くのメソッドを呼ぶ必要がある | オブジェクト内にある |
| OOスタイル | × | ◯ |
| 大量操作 | 扱いにくい | 扱いやすい |
| ストリーム操作 | あり | あり |
情報とオブジェクトの更新
FileInfo / DirectoryInfo のオブジェクトは最初にプロパティへアクセスしたときに値をキャッシュします。インスタンス作成後にファイルやフォルダがディスク上で変わった場合は、情報を更新するために .Refresh() を呼んでください。
var file = new FileInfo("notes.txt");
long oldSize = file.Length;
// この間に誰か(あるいは自分)がプログラム外でファイルを変更する
file.Refresh();
long newSize = file.Length;
これは頻繁にあることではありませんが、プログラムがファイルシステムを監視している場合は重要な仕組みです。
5. インスタンスクラスを使う際の典型的な間違い
誤解: new FileInfo("file.txt") を作ればファイルは既に存在する、というもの。実際は違います — ファイルは明示的に書き込むか Create() を呼ばない限り作成されません。
存在しないファイルのプロパティを取得しようとすると: いくつかのプロパティはデフォルト値(例えばサイズは 0)を返しますが、読み取りストリームを開こうとすると例外になります。
フォルダも同様です: DirectoryInfo を作っただけではディスク上にフォルダが存在する保証にはならず、Create() を呼ぶか本当に作成されるまで存在しません。
GO TO FULL VERSION