CodeGym /コース /C# SELF /インスタンスクラス FileInfo と DirectoryInfo

インスタンスクラス FileInfo と DirectoryInfo

C# SELF
レベル 39, レッスン 1
使用可能

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 の操作

このクラスの主要なプロパティとメソッドを見ていきます。覚え書きはこちら:

プロパティ/メソッド 何を返す? 使用例
Name
ファイル名
fileInfo.Name
FullName
フルパス
fileInfo.FullName
Length
ファイルサイズ(バイト)
fileInfo.Length
Directory
親ディレクトリ(DirectoryInfo)
fileInfo.Directory.FullName
Exists
ファイルが実際に存在するか?
fileInfo.Exists
Extension
拡張子(.txt など)
fileInfo.Extension
CreationTime
作成日時
fileInfo.CreationTime
LastWriteTime
最終更新日時
fileInfo.LastWriteTime
IsReadOnly
読み取り専用か?
fileInfo.IsReadOnly
メソッド
CopyTo()
ファイルをコピー
fileInfo.CopyTo("copy.txt")
Delete()
ファイルを削除
fileInfo.Delete()
MoveTo()
ファイルを移動
fileInfo.MoveTo("move.txt")
OpenRead()
読み取り用ストリームを開く
using var stream = fileInfo.OpenRead()
OpenWrite()
書き込み用ストリームを開く
using var stream = fileInfo.OpenWrite()

例: ファイル情報の取得

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 が何を提供してくれるか見てみましょう:

プロパティ/メソッド 何を返す? 使用例
Name
フォルダ名
dirInfo.Name
FullName
フルパス
dirInfo.FullName
Parent
親フォルダ(DirectoryInfo)
dirInfo.Parent.FullName
Exists
フォルダが存在するか?
dirInfo.Exists
CreationTime
作成日時
dirInfo.CreationTime
LastWriteTime
更新日時
dirInfo.LastWriteTime
メソッド
Create()
フォルダを作成
dirInfo.Create()
Delete()
フォルダを削除
dirInfo.Delete()
GetFiles()
ファイルの配列(FileInfo の配列)
dirInfo.GetFiles()
GetDirectories()
サブフォルダの配列(DirectoryInfo の配列)
dirInfo.GetDirectories()
EnumerateFiles()
ファイルの列挙(IEnumerable<FileInfo> を返す、遅延実行)
dirInfo.EnumerateFiles()
MoveTo()
フォルダを移動
dirInfo.MoveTo("path")

例: ファイルとフォルダの列挙

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() より優れます。遅延列挙はメモリを節約し、処理開始を速くします。

静的アプローチとインスタンスアプローチの比較

静的メソッド インスタンスクラス
構文
File.Delete(path)
new FileInfo(path).Delete()
キャッシュ なし あり
多くの情報 多くのメソッドを呼ぶ必要がある オブジェクト内にある
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() を呼ぶか本当に作成されるまで存在しません。

2
タスク
C# SELF, レベル 39, レッスン 1
ロック未解除
ディレクトリ内のファイル一覧を表示する
ディレクトリ内のファイル一覧を表示する
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION