C#でディレクトリを操作する方法|作成・取得・存在確認・一覧取得・削除をわかりやすく解説
C#では、System.IO名前空間に用意されているクラスを使って、ディレクトリの作成、パスの取得、存在確認、一覧取得、削除などを行えます。
ディレクトリ操作は、ログや設定ファイルの保存先を準備したり、指定フォルダー内のファイルを一括処理したりするときに欠かせません。一方で、カレントディレクトリとアプリケーションの実行ディレクトリを混同する、存在確認後にディレクトリが削除される、アクセス権限のないフォルダーを再帰検索するといった問題も起こりやすいため、各APIの性質を理解しておくことが重要です。
この記事では、C#でディレクトリを操作する基本から、作成、取得、存在確認、ディレクトリ・ファイルの一覧取得まで、サンプルコードを交えて解説します。
1. C#でディレクトリを操作する基本
1-1. ディレクトリ操作で使用するSystem.IO名前空間
C#でディレクトリやファイルを操作するときは、主にSystem.IO名前空間を使用します。
using System.IO;System.IOには、次のようなクラスが用意されています。
Directory:ディレクトリの作成、削除、移動、一覧取得などを行うDirectoryInfo:特定のディレクトリをオブジェクトとして操作するFile:ファイルの作成、コピー、削除、存在確認などを行うFileInfo:特定のファイルをオブジェクトとして操作するPath:パスの結合やファイル名、拡張子、ルートパスの取得を行う
Directoryクラスは、ディレクトリやサブディレクトリを作成、移動、列挙するための静的メソッドを提供しています。
たとえば、ディレクトリを作成する基本的なコードは次のとおりです。
using System.IO;string directoryPath = @"C:\Work\Sample";Directory.CreateDirectory(directoryPath);
1-2. DirectoryクラスとDirectoryInfoクラスの違い
DirectoryクラスとDirectoryInfoクラスは、どちらもC#でディレクトリを操作するために使用しますが、利用方法が異なります。
Directoryは静的クラスであるため、インスタンスを作成せずにメソッドを呼び出します。
string directoryPath = @"C:\Work\Sample";Directory.CreateDirectory(directoryPath);
if (Directory.Exists(directoryPath)){Console.WriteLine("ディレクトリが存在します。");}
一方、DirectoryInfoは、ディレクトリを表すオブジェクトを作成して操作します。
string directoryPath = @"C:\Work\Sample";DirectoryInfo directoryInfo = new DirectoryInfo(directoryPath);directoryInfo.Create();
Console.WriteLine(directoryInfo.FullName);Console.WriteLine(directoryInfo.Name);
一度だけ作成や存在確認を行う場合は、記述が簡潔なDirectoryが向いています。同じディレクトリに対して、名前や親ディレクトリ、作成日時などの情報を繰り返し取得する場合は、DirectoryInfoを使うとコードをまとめやすくなります。
DirectoryInfoでは、サブディレクトリやファイルをDirectoryInfo[]、FileInfo[]として取得できる点も特徴です。
1-3. 絶対パスと相対パスの違い
ディレクトリのパスには、絶対パスと相対パスがあります。
絶対パスは、ドライブやルートディレクトリから目的のディレクトリまでを完全に指定する形式です。
string absolutePath = @"C:\Work\Sample";相対パスは、現在の作業ディレクトリを基準に指定する形式です。
string relativePath = @"data\images";相対パスをDirectory.CreateDirectoryなどに渡すと、カレントディレクトリを基準として処理されます。
Directory.CreateDirectory(@"data\images");相対パスを絶対パスに変換するには、Path.GetFullPathを使用します。
string relativePath = @"data\images";string fullPath = Path.GetFullPath(relativePath);Console.WriteLine(fullPath);
相対パスの基準となるカレントディレクトリは変更される可能性があります。特に複数の実行環境で動かすアプリケーションでは、基準となるパスを明示し、絶対パスへ変換してから利用すると安全です。
パスが完全な絶対パスか確認したい場合は、Path.IsPathFullyQualifiedも利用できます。
string path = @"C:\Work\Sample";if (Path.IsPathFullyQualified(path)){Console.WriteLine("完全修飾されたパスです。");}
1-4. Path.Combineで安全にディレクトリパスを作成する方法
ディレクトリパスを文字列として作成するときは、区切り文字を直接連結するのではなく、Path.Combineを使用するのが基本です。
string baseDirectory = @"C:\Work";string directoryPath = Path.Combine(baseDirectory, "data", "images");Console.WriteLine(directoryPath);
Windowsでは一般的に区切り文字として</span>を使いますが、LinuxやmacOSでは/が使われます。Path.Combineを使用すると、実行環境に応じた区切り文字でパスを組み立てられます。
次のように文字列を直接連結する方法は、区切り文字の不足や重複が起こりやすいため避けましょう。
// 推奨しない例string path = baseDirectory + "\" + "data" + "\" + "images";なお、Path.Combineの2番目以降に絶対パスを渡すと、それ以前のパス要素は無視されます。
string path = Path.Combine(@"C:\Work", @"D:\Data");// 結果は D:\DataConsole.WriteLine(path);
ユーザー入力をパスの一部に利用する場合は、絶対パスや..が含まれていないか確認し、作成されたパスが想定する基準ディレクトリ内に収まっていることも検証してください。
2. C#でディレクトリを作成する方法
2-1. Directory.CreateDirectoryでディレクトリを作成する
C#でディレクトリを作成する場合は、Directory.CreateDirectoryを使用します。
using System.IO;string directoryPath = @"C:\Work\Sample";Directory.CreateDirectory(directoryPath);
CreateDirectoryの戻り値は、作成対象のディレクトリを表すDirectoryInfoです。
DirectoryInfo createdDirectory =Directory.CreateDirectory(@"C:\Work\Sample");Console.WriteLine(createdDirectory.FullName);
相対パスを指定することもできます。
Directory.CreateDirectory("output");この場合は、現在の作業ディレクトリ内にoutputディレクトリが作成されます。
2-2. 複数階層のディレクトリを一括で作成する
Directory.CreateDirectoryでは、途中のディレクトリが存在しない場合でも、必要な階層をまとめて作成できます。
string directoryPath =Path.Combine(@"C:\Work", "data", "2026", "images");Directory.CreateDirectory(directoryPath);
たとえば、C:\Work\dataやC:\Work\data\2026が存在しない場合でも、必要な親ディレクトリが順番に作成されます。
アプリケーションの実行ディレクトリ内に複数階層のフォルダーを作る場合は、次のように記述できます。
string directoryPath = Path.Combine(AppContext.BaseDirectory,"data","logs",DateTime.Today.ToString("yyyyMMdd"));Directory.CreateDirectory(directoryPath);
2-3. DirectoryInfoでディレクトリを作成する
DirectoryInfoを使ってディレクトリを作成する場合は、対象パスをコンストラクターに渡し、Createメソッドを呼び出します。
string directoryPath = @"C:\Work\Sample";DirectoryInfo directoryInfo = new DirectoryInfo(directoryPath);directoryInfo.Create();
作成後は、同じオブジェクトからディレクトリ名やフルパス、親ディレクトリなどを取得できます。
Console.WriteLine($"名前: {directoryInfo.Name}");Console.WriteLine($"フルパス: {directoryInfo.FullName}");Console.WriteLine($"親: {directoryInfo.Parent?.FullName}");DirectoryInfoの一部のプロパティ情報はキャッシュされることがあります。外部処理によってディレクトリの状態が変更される可能性がある場合は、Refreshメソッドで情報を更新できます。
directoryInfo.Refresh();Console.WriteLine(directoryInfo.Exists);
2-4. すでに存在するディレクトリを作成した場合の動作
Directory.CreateDirectoryは、指定したディレクトリがすでに存在していても、通常は例外を発生させません。既存のディレクトリを表すDirectoryInfoが返されます。
string directoryPath = @"C:\Work\Sample";Directory.CreateDirectory(directoryPath);Directory.CreateDirectory(directoryPath);
Console.WriteLine("処理が完了しました。");
そのため、ディレクトリを確実に用意したいだけであれば、事前にDirectory.Existsで確認しなくても、直接CreateDirectoryを呼び出せます。
string directoryPath = @"C:\Work\Sample";Directory.CreateDirectory(directoryPath);ただし、同じパスにファイルが存在する場合や、書き込み権限がない場合、パスが不正な場合などは例外が発生します。実運用では、必要に応じてUnauthorizedAccessExceptionやIOExceptionなどを処理してください。
try{Directory.CreateDirectory(@"C:\Work\Sample");}catch (UnauthorizedAccessException ex){Console.WriteLine($"アクセス権限がありません: {ex.Message}");}catch (IOException ex){Console.WriteLine($"入出力エラーが発生しました: {ex.Message}");}作成したディレクトリを削除するときは、Directory.Deleteを使用します。引数がパスだけの場合は、空のディレクトリのみ削除できます。
string directoryPath = @"C:\Work\Sample";if (Directory.Exists(directoryPath)){Directory.Delete(directoryPath);}
ファイルやサブディレクトリを含めて再帰的に削除する場合は、第2引数にtrueを指定します。
Directory.Delete(directoryPath, recursive: true);再帰削除では配下のファイルもすべて削除され、基本的に元へ戻せません。削除対象のフルパスを確認し、アプリケーションが管理するディレクトリ以外を削除できないように制限することが重要です。
3. C#でディレクトリのパスを取得する方法
3-1. カレントディレクトリを取得する
現在の作業ディレクトリを取得するには、Directory.GetCurrentDirectoryを使用します。
string currentDirectory = Directory.GetCurrentDirectory();Console.WriteLine(currentDirectory);
Environment.CurrentDirectoryでも、現在の作業ディレクトリを取得できます。
string currentDirectory = Environment.CurrentDirectory;Console.WriteLine(currentDirectory);
カレントディレクトリは、アプリケーションの実行ファイルが置かれているディレクトリと一致するとは限りません。コマンドを実行した場所、IDEの設定、サービスとしての実行などによって変化します。Directory.GetCurrentDirectoryは、現在の作業ディレクトリの絶対パスを返します。
3-2. アプリケーションの実行ディレクトリを取得する
アプリケーションの基準ディレクトリを取得したい場合は、AppContext.BaseDirectoryを使用できます。
string applicationDirectory = AppContext.BaseDirectory;Console.WriteLine(applicationDirectory);
AppContext.BaseDirectoryは、アセンブリの解決に使用されるベースディレクトリのパスを返します。
アプリケーションと同じ場所にあるconfigディレクトリのパスを作る場合は、次のように記述します。
string configDirectory = Path.Combine(AppContext.BaseDirectory,"config");Directory.CreateDirectory(configDirectory);
Directory.GetCurrentDirectoryとAppContext.BaseDirectoryは目的が異なります。
Console.WriteLine($"カレント: {Directory.GetCurrentDirectory()}");Console.WriteLine($"実行基準: {AppContext.BaseDirectory}");
ユーザーが作業場所を切り替えられるツールではカレントディレクトリ、アプリケーションに付属する設定ファイルなどを参照する場合はAppContext.BaseDirectoryというように使い分けます。
3-3. 親ディレクトリを取得する
指定したディレクトリの親を取得するには、Directory.GetParentを使用します。
string directoryPath = @"C:\Work\data\images";DirectoryInfo? parentDirectory =Directory.GetParent(directoryPath);
if (parentDirectory is not null){Console.WriteLine(parentDirectory.FullName);}
DirectoryInfo.Parentから取得する方法もあります。
DirectoryInfo directoryInfo =new DirectoryInfo(@"C:\Work\data\images");DirectoryInfo? parentDirectory = directoryInfo.Parent;
Console.WriteLine(parentDirectory?.FullName ?? "親ディレクトリはありません。");
ドライブのルートなど、親ディレクトリが存在しないパスではnullになる可能性があるため、nullチェックを行いましょう。
ファイルパスから、そのファイルが含まれるディレクトリ部分を取得する場合は、Path.GetDirectoryNameを使用します。
string filePath = @"C:\Work\data\sample.txt";string? directoryPath = Path.GetDirectoryName(filePath);Console.WriteLine(directoryPath);
Path.GetDirectoryNameは、指定されたパスのディレクトリ情報を返します。
3-4. ディレクトリ名とルートパスを取得する
ディレクトリの名前だけを取得する場合は、DirectoryInfo.Nameが分かりやすい方法です。
DirectoryInfo directoryInfo =new DirectoryInfo(@"C:\Work\data");Console.WriteLine(directoryInfo.Name);
実行結果は次のようになります。
data文字列のパスから末尾のディレクトリ名を取得する場合は、末尾の区切り文字を除去してからPath.GetFileNameを使用します。
string directoryPath = @"C:\Work\data";string directoryName = Path.GetFileName(Path.TrimEndingDirectorySeparator(directoryPath));
Console.WriteLine(directoryName);
ルートパスを取得するには、Path.GetPathRootを使用します。
string directoryPath = @"C:\Work\data";string? rootPath = Path.GetPathRoot(directoryPath);Console.WriteLine(rootPath);
WindowsではC:</span>、ネットワーク上のUNCパスでは共有ルートなどが返されます。
3-5. デスクトップやドキュメントなどの特殊フォルダーを取得する
デスクトップやドキュメントなど、OSが管理する特殊フォルダーのパスを取得するには、Environment.GetFolderPathを使用します。
デスクトップのパスを取得するコードは次のとおりです。
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);Console.WriteLine(desktopPath);
ドキュメントフォルダーは、MyDocumentsを指定して取得します。
string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);Console.WriteLine(documentsPath);
アプリケーションデータの保存先を取得する例は次のとおりです。
string applicationDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);string applicationDirectory = Path.Combine(applicationDataPath,"SampleApplication");
Directory.CreateDirectory(applicationDirectory);
ユーザーフォルダーの場所はOSの設定によって異なるため、C:\Users\ユーザー名\Documentsなどの文字列を固定して指定するのではなく、Environment.GetFolderPathを利用するのが適切です。
4. C#でディレクトリの存在を確認する方法
4-1. Directory.Existsでディレクトリの存在を確認する
ディレクトリが存在するか確認するには、Directory.Existsを使用します。
string directoryPath = @"C:\Work\Sample";bool exists = Directory.Exists(directoryPath);
Console.WriteLine(exists);
条件分岐と組み合わせる場合は、次のように記述します。
if (Directory.Exists(directoryPath)){Console.WriteLine("ディレクトリが存在します。");}else{Console.WriteLine("ディレクトリが存在しません。");}Directory.Existsは、指定したパスが既存のディレクトリを参照している場合にtrueを返します。ディレクトリが存在しない場合だけでなく、存在を確認するときにエラーが発生した場合もfalseを返します。
4-2. 存在しない場合だけディレクトリを作成する
存在しない場合だけディレクトリを作成したい場合は、次のように記述できます。
string directoryPath = @"C:\Work\Sample";if (!Directory.Exists(directoryPath)){Directory.CreateDirectory(directoryPath);}
ただし、ディレクトリを確実に用意することだけが目的であれば、CreateDirectoryを直接呼び出すほうが簡潔です。
string directoryPath = @"C:\Work\Sample";Directory.CreateDirectory(directoryPath);すでにディレクトリが存在していても、CreateDirectoryは既存のディレクトリをそのまま扱います。そのため、単純な作成処理では存在確認を省略できます。
存在しなかったときだけメッセージを表示するなど、処理を分ける必要がある場合はDirectory.Existsを使用します。
string directoryPath = @"C:\Work\Sample";bool alreadyExists = Directory.Exists(directoryPath);
Directory.CreateDirectory(directoryPath);
if (!alreadyExists){Console.WriteLine("新しいディレクトリを作成しました。");}
4-3. ファイルとディレクトリを判別する
指定したパスがファイルかディレクトリか判別するには、File.ExistsとDirectory.Existsを組み合わせます。
string path = @"C:\Work\Sample";if (File.Exists(path)){Console.WriteLine("ファイルです。");}else if (Directory.Exists(path)){Console.WriteLine("ディレクトリです。");}else{Console.WriteLine("ファイルまたはディレクトリが存在しません。");}
同じパスにファイルとディレクトリが同時に存在することは通常ないため、順番に確認することで種類を判定できます。
ただし、どちらもfalseだからといって、必ずしも対象が存在しないとは限りません。アクセス権限の不足や不正なパスなどが原因で、存在を確認できていない可能性もあります。
4-4. 存在確認を行う際の注意点
Directory.Existsでtrueを確認した直後でも、別のプログラムやスレッドによってディレクトリが削除される可能性があります。
if (Directory.Exists(directoryPath)){// この時点で削除される可能性があるstring[] files = Directory.GetFiles(directoryPath);}そのため、存在確認だけに依存せず、実際の操作で発生する例外も処理する必要があります。
try{string[] files = Directory.GetFiles(directoryPath);foreach (string file in files){Console.WriteLine(file);}
}catch (DirectoryNotFoundException){Console.WriteLine("処理中にディレクトリが見つからなくなりました。");}catch (UnauthorizedAccessException){Console.WriteLine("ディレクトリへアクセスする権限がありません。");}catch (IOException ex){Console.WriteLine($"入出力エラー: {ex.Message}");}
また、Directory.Existsは、無効なパスやアクセス権限のないパスなどに対して例外を投げず、falseを返すことがあります。falseを「確実に存在しない」という意味だけで扱わないことが大切です。
5. C#でディレクトリの一覧を取得する方法
5-1. Directory.GetDirectoriesでサブディレクトリ一覧を取得する
指定したディレクトリ直下にあるサブディレクトリの一覧を取得するには、Directory.GetDirectoriesを使用します。
string baseDirectory = @"C:\Work";string[] directories =Directory.GetDirectories(baseDirectory);
foreach (string directory in directories){Console.WriteLine(directory);}
戻り値はstring[]で、それぞれの要素にはディレクトリのパスが入ります。
ディレクトリ名だけを表示したい場合は、DirectoryInfo.NameまたはPath.GetFileNameを使用します。
foreach (string directory in directories){string name = new DirectoryInfo(directory).Name;Console.WriteLine(name);}GetDirectoriesは、条件に一致するサブディレクトリの情報を配列としてまとめて返します。
5-2. 検索パターンを指定してディレクトリを絞り込む
Directory.GetDirectoriesの第2引数には、検索パターンを指定できます。
名前がdataで始まるディレクトリを取得する例は次のとおりです。
string baseDirectory = @"C:\Work";string[] directories =Directory.GetDirectories(baseDirectory, "data*");
foreach (string directory in directories){Console.WriteLine(directory);}
検索パターンでは、主に次のワイルドカードを使用します。
:0文字以上の任意の文字列?:任意の1文字
たとえば、logで始まるディレクトリを検索する場合はlog、dataの後ろに1文字だけ付くディレクトリを検索する場合はdata?を指定します。
string[] logDirectories =Directory.GetDirectories(baseDirectory, "log*");string[] numberedDirectories =Directory.GetDirectories(baseDirectory, "data?");
検索パターンは、正規表現ではありません。複雑な条件で絞り込む場合は、一覧を取得した後にLINQを使用します。
5-3. SearchOptionで配下のディレクトリを再帰的に取得する
第3引数にSearchOptionを指定すると、直下だけでなく、配下のディレクトリを再帰的に検索できます。
string baseDirectory = @"C:\Work";string[] directories = Directory.GetDirectories(baseDirectory,"*",SearchOption.AllDirectories);
foreach (string directory in directories){Console.WriteLine(directory);}
SearchOptionの主な値は次の2つです。
SearchOption.TopDirectoryOnly:指定したディレクトリの直下だけを検索するSearchOption.AllDirectories:すべてのサブディレクトリを再帰的に検索する
直下だけを明示的に検索する場合は、次のように記述します。
string[] directories = Directory.GetDirectories(baseDirectory,"*",SearchOption.TopDirectoryOnly);AllDirectoriesを指定すると、アクセス権限のないサブディレクトリが含まれていた場合に、UnauthorizedAccessExceptionが発生する可能性があります。対象範囲が広い場合は、例外処理を行うか、EnumerationOptionsを利用してアクセスできない項目を無視する方法も検討します。
EnumerationOptions options = new EnumerationOptions{RecurseSubdirectories = true,IgnoreInaccessible = true};IEnumerable<string> directories =Directory.EnumerateDirectories(baseDirectory,"*",options);
5-4. Directory.EnumerateDirectoriesで一覧を逐次取得する
Directory.EnumerateDirectoriesを使用すると、ディレクトリを一件ずつ列挙できます。
string baseDirectory = @"C:\Work";IEnumerable<string> directories =Directory.EnumerateDirectories(baseDirectory);
foreach (string directory in directories){Console.WriteLine(directory);}
検索パターンや再帰検索も指定できます。
IEnumerable<string> directories =Directory.EnumerateDirectories(baseDirectory,"data*",SearchOption.AllDirectories);foreach (string directory in directories){Console.WriteLine(directory);}
列挙は遅延実行されるため、通常はforeachなどで要素を要求した時点から実際の検索が進みます。
5-5. GetDirectoriesとEnumerateDirectoriesの違い
GetDirectoriesとEnumerateDirectoriesの大きな違いは、結果を返す方法です。
GetDirectoriesは、対象となるディレクトリをすべて取得してからstring[]として返します。
string[] directories =Directory.GetDirectories(baseDirectory);一方、EnumerateDirectoriesは、IEnumerable<string>を返し、結果を順番に列挙します。
IEnumerable<string> directories =Directory.EnumerateDirectories(baseDirectory);対象が少なく、結果全体を何度も使いたい場合はGetDirectoriesが分かりやすい方法です。対象が非常に多い場合や、見つかったものから順番に処理したい場合は、EnumerateDirectoriesが適しています。
列挙形式のAPIは、配列を返すAPIと比べ、コレクション全体が返される前に処理を開始できます。大量のディレクトリやファイルを扱う場合に有効です。
ただし、EnumerateDirectoriesで発生する例外は、メソッドを呼び出した時点ではなく、foreachで列挙している途中に発生する場合があります。
try{foreach (string directory inDirectory.EnumerateDirectories(baseDirectory)){Console.WriteLine(directory);}}catch (UnauthorizedAccessException ex){Console.WriteLine($"アクセスエラー: {ex.Message}");}5-6. LINQを使って取得したディレクトリを並べ替える
取得したディレクトリを名前順に並べ替える場合は、LINQのOrderByを使用します。
using System.Linq;string baseDirectory = @"C:\Work";
IEnumerable<string> directories =Directory.EnumerateDirectories(baseDirectory).OrderBy(path => Path.GetFileName(path),StringComparer.OrdinalIgnoreCase);
foreach (string directory in directories){Console.WriteLine(directory);}
降順に並べ替える場合は、OrderByDescendingを使用します。
IEnumerable<string> directories =Directory.EnumerateDirectories(baseDirectory).OrderByDescending(path => Path.GetFileName(path),StringComparer.OrdinalIgnoreCase);更新日時の新しい順に並べることもできます。
IEnumerable<DirectoryInfo> directories =new DirectoryInfo(baseDirectory).EnumerateDirectories().OrderByDescending(directory => directory.LastWriteTimeUtc);foreach (DirectoryInfo directory in directories){Console.WriteLine($"{directory.Name}: {directory.LastWriteTime}");}
並べ替えを行うと、結果を比較するために列挙対象を保持する必要があります。そのため、大量のディレクトリを単純に順次処理したい場合は、不要な並べ替えを行わないほうが効率的です。
6. C#でディレクトリ内のファイル一覧を取得する方法
6-1. Directory.GetFilesでファイル一覧を取得する
指定したディレクトリ内にあるファイルの一覧を取得するには、Directory.GetFilesを使用します。
string directoryPath = @"C:\Work\data";string[] files = Directory.GetFiles(directoryPath);
foreach (string file in files){Console.WriteLine(file);}
Directory.GetFilesは、指定したディレクトリ内にあるファイルのパスをstring[]として返します。
ファイル名だけを表示する場合は、Path.GetFileNameを使用します。
foreach (string file in files){Console.WriteLine(Path.GetFileName(file));}拡張子を除いたファイル名を取得する場合は、Path.GetFileNameWithoutExtensionを使用します。
foreach (string file in files){string fileName =Path.GetFileNameWithoutExtension(file);Console.WriteLine(fileName);
}
6-2. 拡張子を指定してファイルを検索する
特定の拡張子を持つファイルだけを取得する場合は、第2引数に検索パターンを指定します。
string directoryPath = @"C:\Work\data";string[] textFiles =Directory.GetFiles(directoryPath, "*.txt");
foreach (string file in textFiles){Console.WriteLine(file);}
CSVファイルを検索する場合は、次のように指定します。
string[] csvFiles =Directory.GetFiles(directoryPath, "*.csv");複数の拡張子を検索したい場合は、一度一覧を列挙してLINQで絞り込む方法があります。
string[] targetExtensions ={".jpg",".jpeg",".png"};IEnumerable<string> imageFiles =Directory.EnumerateFiles(directoryPath).Where(file =>targetExtensions.Contains(Path.GetExtension(file),StringComparer.OrdinalIgnoreCase));
foreach (string file in imageFiles){Console.WriteLine(file);}
拡張子を文字列のEndsWithだけで判定すると、意図しないファイル名に一致する可能性があります。Path.GetExtensionを使用すると、拡張子部分を明確に取得できます。
6-3. サブディレクトリを含めてファイルを再帰検索する
サブディレクトリ内のファイルも含めて取得するには、SearchOption.AllDirectoriesを指定します。
string directoryPath = @"C:\Work\data";string[] files = Directory.GetFiles(directoryPath,"*",SearchOption.AllDirectories);
foreach (string file in files){Console.WriteLine(file);}
特定の拡張子に絞り込みながら再帰検索することもできます。
string[] logFiles = Directory.GetFiles(directoryPath,"*.log",SearchOption.AllDirectories);アクセスできないディレクトリを無視しながら再帰検索したい場合は、EnumerationOptionsを使用できます。
EnumerationOptions options = new EnumerationOptions{RecurseSubdirectories = true,IgnoreInaccessible = true,ReturnSpecialDirectories = false};IEnumerable<string> logFiles =Directory.EnumerateFiles(directoryPath,"*.log",options);
foreach (string file in logFiles){Console.WriteLine(file);}
再帰検索では非常に多くのファイルが対象になる場合があります。処理対象のルートパスが正しいか確認し、必要に応じて検索パターンや対象階層を制限してください。
6-4. Directory.EnumerateFilesで大量のファイルを効率よく取得する
大量のファイルを扱う場合は、Directory.EnumerateFilesを使用すると、見つかったファイルから順番に処理できます。
string directoryPath = @"C:\Work\data";IEnumerable<string> files =Directory.EnumerateFiles(directoryPath);
foreach (string file in files){Console.WriteLine(file);}
たとえば、ログファイルを一件ずつ読み込んで処理する場合は、次のように記述できます。
IEnumerable<string> logFiles =Directory.EnumerateFiles(directoryPath,"*.log",SearchOption.AllDirectories);foreach (string logFile in logFiles){ProcessLogFile(logFile);}
static void ProcessLogFile(string filePath){Console.WriteLine($"処理中: {filePath}");
// 実際のファイル処理を記述する
}
条件に一致する最初のファイルだけを探す処理にも適しています。
string? firstCsvFile =Directory.EnumerateFiles(directoryPath,"*.csv",SearchOption.AllDirectories).FirstOrDefault();if (firstCsvFile is not null){Console.WriteLine(firstCsvFile);}
GetFilesはすべてのファイル名を取得してから配列を返しますが、EnumerateFilesではコレクション全体が返される前に列挙を開始できます。大量のファイルを順番に処理する用途では、使用メモリを抑えやすく、最初の結果に早くアクセスできます。
まとめ
C#でディレクトリを操作するときは、主にSystem.IO名前空間のDirectory、DirectoryInfo、Pathを使用します。
ディレクトリを作成する場合はDirectory.CreateDirectory、存在確認にはDirectory.Exists、一覧取得にはDirectory.GetDirectoriesまたはDirectory.EnumerateDirectoriesを使用します。ディレクトリ内のファイル一覧は、Directory.GetFilesまたはDirectory.EnumerateFilesで取得できます。
パスを組み立てる際は、文字列を直接連結せず、Path.Combineを使うことが重要です。また、カレントディレクトリを取得するDirectory.GetCurrentDirectoryと、アプリケーションの基準ディレクトリを取得するAppContext.BaseDirectoryは、目的に応じて使い分けましょう。
ディレクトリを削除する場合は、空のディレクトリならDirectory.Delete(path)、配下のファイルやサブディレクトリも削除するならDirectory.Delete(path, true)を使用します。ただし、再帰削除はデータをまとめて失う危険があるため、削除対象のパスを十分に検証する必要があります。
大量のディレクトリやファイルを扱う場合は、結果を一括取得するGetDirectoriesやGetFilesよりも、逐次取得するEnumerateDirectoriesやEnumerateFilesが適しています。
最後に、存在確認を行った後でも、実際の操作までにディレクトリの状態が変化する可能性があります。Directory.Existsだけに依存せず、UnauthorizedAccessException、DirectoryNotFoundException、IOExceptionなど、実際のディレクトリ操作で発生する例外も適切に処理することが、安全なC#プログラムを作成するポイントです。

