System.IO名前空間に用意されているクラスを使うことでファイルやディレクトリ(フォルダ)などファイルシステムに対する操作を行うことができます。 例えば、ファイルのコピー・削除・移動などの操作はFileクラス、ディレクトリの作成・削除・移動などの操作はDirectoryクラスのメソッドを使います。 また、FileInfo・DirectoryInfoのインスタンスを作成・取得することでファイルやディレクトリのプロパティを取得することもできます。
ここでは、System.IO名前空間にあるクラスのうち、ファイルやディレクトリのコピー・削除・移動など、ファイルシステムの操作に関するクラスの使い方について解説します。 ファイルに対する読み込み・書き込みについてはファイル入出力、あるいはFileStreamクラスやStreamReaderクラス・StreamWriterクラスにて個別に解説していますのでそちらをご覧ください。
なお、ここではフォルダという用語は使わずクラス名にも使われているディレクトリで統一します。
本文中のサンプルではパスを記述するために逐語的文字列リテラルを使用している個所があります。
ディレクトリの走査・ファイルの検索
ディレクトリを走査してディレクトリ内に含まれるファイルやサブディレクトリを取得するには、Directoryクラスに用意されているメソッドを使います。 単純な走査だけでなく、ワイルドカードによるパターンマッチングを使った検索や、ディレクトリ内の再帰的な走査も行うことができます。
ディレクトリ内にあるすべてのファイルを取得するにはGetFilesメソッド、サブディレクトリを取得するにはGetDirectoriesメソッドを使います。 これらのメソッドでは、引数として取得の対象となるディレクトリを相対パスまたは絶対パスで指定します。 存在しないディレクトリを指定した場合は例外DirectoryNotFoundExceptionがスローされます。
GetFiles・GetDirectoriesメソッドで特にオプションを指定しない場合、取得されるのは指定したディレクトリ直下にあるファイル・サブディレクトリのみとなります。 この動作を変更するには後述するSearchOptionを指定する必要があります。
GetFileSystemEntriesメソッドを使うと指定ディレクトリにあるファイルとサブディレクトリの両方をまとめて取得することができます。 このメソッドはGetFilesとGetDirectoriesの結果を組み合わせたものと同等となります。
ワイルドカードを指定した検索
GetFiles・GetDirectories・GetFileSystemEntriesの各メソッドは引数にワイルドカードを指定することにより、ワイルドカードにマッチするファイル・サブディレクトリだけを取得するようにすることもできます。 引数にワイルドカードを指定しない場合はすべてのファイル・サブディレクトリが取得されます。 *
を指定した場合も同様にすべてのファイル・サブディレクトリが取得されます。
ワイルドカードには任意の1文字を表す?
および任意の0文字以上を表す*
を含めることができます。
GetFilesメソッド・GetDirectoriesメソッドでは正規表現を使ったマッチングはできないので、必要な場合はワイルドカードを指定する代わりにRegexクラスを使って独自にコードを記述する必要があります。
ディレクトリ走査のオプション (SearchOption)
引数にSearchOptionを指定することにより、サブディレクトリを再帰的に走査するかどうかを指定することができます。 SearchOption.TopDirectoryOnly
を指定した場合は対象のディレクトリ直下のみを走査し、SearchOption.AllDirectories
を指定した場合は対象のディレクトリ内とそのサブディレクトリすべてを再帰的に走査します。
列挙子によるディレクトリの走査
ファイル・ディレクトリの走査するメソッドにはGetFiles/GetDirectories/GetFileSystemEntriesだけでなくEnumerateFiles/EnumerateDirectories/EnumerateFileSystemEntriesというメソッドも用意されています。 これは.NET Framework 4で追加されたメソッドで、どちらも基本的な使い方や得られる結果は同じですが、動作が異なります。
GetFilesメソッドは見つかったファイル・ディレクトリを配列で返すのに対して、EnumerateFilesメソッドはIEnumerable<string>で返します。 GetFilesメソッドではすべてのファイル・ディレクトリの走査が終わるまで結果が返されないのに対して、EnumerateFilesメソッドではメソッドの呼び出し自体は即座に終了し、走査はIEnumerable<string>を列挙する際に開始され、見つかったファイルが順次返されます。 従って、条件に一致するもののうち最初に見つかったものだけを取得したい場合などにはEnumerateFilesメソッドを使った方が効率的です。
上記のコードでは実行結果はどちらも同じとなりますが、仮にディレクトリ内に多数のファイルがある場合、GetFilesメソッドではそのすべてを含む配列が返されるまで列挙が始まらないのに対し、EnumerateFilesでは見つかったファイルから順次列挙されていくことになります。 従って、一般的にGetFilesよりもEnumerateFilesを使った方がよいパフォーマンスが得られます。
一方、EnumerateFilesメソッドから返されるIEnumerable<string>は、列挙を行う度にディレクトリが再走査されます。 従って、EnumerateFilesメソッドで得られる結果を何度も列挙するような場合には、EnumerateFilesよりもGetFilesメソッドを使ったほうがよいパフォーマンスが得られます。
GetFiles/EnumerateFilesだけでなく、GetDirectories/EnumerateDirectoriesおよびGetFileSystemEntries/EnumerateFileSystemEntriesでもこのような特性となります。
走査結果の順序とソート
GetFiles・EnumerateFilesなどディレクトリの走査を行うメソッドは、どのような順序で結果が返されるかは規定されていません。 従って、ファイルやディレクトリの検索結果を名前順や更新日時順にしたいといった場合は、別途ソートを行う必要があります。
次の例では、GetFilesメソッドで取得したファイルをソートし、GetLastWriteTimeメソッドによって取得した最終書き込み日時の順となるようにして表示しています。 ソートにはArray.Sortメソッドを使っています。
次の例は先の例と同じくファイルを最終書き込み日時の順にして表示していますが、EnumerateFilesメソッドとOrderByメソッドを使うようにしています。
ソートについて詳しくは基本型のソートと昇順・降順でのソートおよび複合型のソート・複数キーでのソートで解説しています。
ディレクトリに対する操作 (Directoryクラス)
ディレクトリの作成・削除・移動などの操作を行うにはDirectoryクラスのメソッドを使います。 以下で解説するメソッドでは、操作対象となるディレクトリを引数で指定します。 ワイルドカードや正規表現によるパターンマッチングを使って複数のディレクトリをまとめて削除したり移動することはできないので、そういった場合にはDirectory.GetDirectoriesメソッドと組み合わせて使う必要があります。
存在するか調べる (Directory.Exists)
ディレクトリが存在するかどうかを確かめるにはExistsメソッドを使用します。
作成 (Directory.CreateDirectory)
ディレクトリを作成するにはCreateDirectoryメソッドを使用します(メソッド名はCreate
ではないので注意)。 このメソッドでは引数で指定した名前のディレクトリが作成されますが、指定したディレクトリ名が階層をなす場合(dir\subdir1\subdir2
などサブディレクトリを含む場合)はサブディレクトリも含めて一度に作成されます。 このメソッドは、作成されたディレクトリ(既に存在している場合はそのディレクトリ)のDirectoryInfoを返します。
CreateDirectoryメソッドはすでにディレクトリが存在する場合でも例外はスローされずメソッドは成功します。 そのため、事前にディレクトリが存在するかチェックし、存在しない場合のみCreateDirectoryメソッドで作成する、といったことをする必要はありません。
削除 (Directory.Delete)
ディレクトリを削除するにはDeleteメソッドを使用します。 このメソッドは対象のディレクトリが空の場合のみディレクトリを削除できます。 対象のディレクトリにファイルやサブディレクトリが存在する場合にはIOExceptionをスローします。 ファイルやサブディレクトリを含めて再帰的に削除したい場合は、二番目の引数recursiveにtrue
を指定します。 また、ディレクトリが別のプロセスによって使用されていて削除できない場合にもIOExceptionをスローするので注意が必要です。
移動・リネーム (Directory.Move)
ディレクトリを移動(リネーム)するにはMoveメソッドを使用します。
このメソッドでは既に存在するディレクトリ名へのリネームや移動元の子ディレクトリとなるようなディレクトリに移動することはできません。 そういった場合は、ディレクトリ内のファイル・サブディレクトリを個別に移動する必要があります。 また、異なるドライブ(ボリューム)への移動もサポートされません。 この場合は移動先へのコピーを行ったのち、移動元を削除することによって移動する必要があります。
コピー
Directoryクラスにはディレクトリごと別のディレクトリにコピーするメソッドは用意されていません。 そのため、GetFileSystemEntriesなどのメソッドによってディレクトリ内のファイル・サブディレクトリを再帰的に列挙し、1つづつコピーしていく必要があります。
以下のコードは、ディレクトリのコピーを行うメソッドの例です。
ファイルに対する操作 (Fileクラス)
ファイルのコピー・削除・移動などの操作を行うにはFileクラスのメソッドを使います。 以下で解説するメソッドでは、操作対象となるファイルを引数で指定します。 ワイルドカードや正規表現によるパターンマッチングを使って複数のファイルをまとめて削除したり移動することはできないので、そういった場合にはDirectory.GetFilesメソッドと組み合わせて使う必要があります。
存在するか調べる (File.Exists)
ファイルが存在するかどうかを確かめるにはExistsメソッドを使用します。
削除 (File.Delete)
ファイルを削除するにはDeleteメソッドを使用します。 ファイルが別のプロセスによって使用されていて削除できない場合にはIOExceptionをスローするので注意が必要です。
移動・リネーム (File.Move)
ファイルを移動(リネーム)するにはMoveメソッドを使用します。
このメソッドでは既に存在するファイル名へリネームすることはできません。 したがって、Moveメソッドによるファイルのリネームではファイルの上書きが行われることはありません。 存在するファイル名へのリネームを行おうとした場合にはIOExceptionがスローされます。 また、移動先のディレクトリが存在しない場合にはDirectoryNotFoundExceptionがスローされるため、事前に移動先のディレクトリを作成しておく必要があります。
ファイルのコピー (File.Copy)
ファイルをコピーするにはCopyメソッドを使用します。 三番目の引数overwriteにtrue
を指定するとコピー先のファイルが存在する場合に上書きを許可します。 指定しなかった場合、もしくはfalse
を指定した場合では、コピー先のファイルが存在する場合にはIOExceptionがスローされます。
Moveメソッドと同様、コピー先のディレクトリが存在しない場合にはDirectoryNotFoundExceptionがスローされるため、事前にコピー先のディレクトリを作成しておく必要があります。
ファイルの作成・オープン (File.Create, File.Open)
Fileクラスには既存のファイルを開くOpenメソッドや、新しくファイルを作成または上書きして開くCreateメソッドが用意されています。
開いたファイルへの読み書きは、Createメソッド・Openメソッドが返すFileStreamを使って行います。 これらのメソッドとFileStreamについてはFileStreamクラスで解説しています。
開いたファイルを使ってテキストを読み書きする方法についてはStreamReaderクラス・StreamWriterクラス、バイナリの読み書きを行う方法についてはBinaryReaderクラス・BinaryWriterクラスを参照してください。
ファイル属性
GetAttributes・SetAttributesメソッドを使うことでファイル属性の取得・設定を行うことができます。 このメソッドでは、属性をブール型や整数型ではなくFileAttributes列挙体のビットごとの組み合わせによって表現します。
列挙体とビットごとの組み合わせについては列挙体とフラグや列挙体の基本と操作 §.値が特定のフラグを持つか (HasFlags)を参照してください。
Monoの場合、非Windows環境では読み取り専用の属性のみがエミュレートされ、それ以外の属性は無視されます。 ファイルパーミッションの変更を行いたい場合は、Mono.Unix.UnixFileInfoクラスのProtectionプロパティを使う必要があります。 Mono.Posix.dllを参照に追加することでこれらのクラスを使用することができます。
タイムスタンプ
Fileクラスにはファイルのタイムスタンプを扱う以下のようなメソッドが用意されています。 ファイルだけでなくディレクトリのタイムスタンプを取得・設定する場合もこれらのメソッドを使うことができます。 同名のメソッドはDirectoryクラスにも用意されていて、同じくディレクトリだけでなくファイルのタイムスタンプを取得・設定できるようになっています。
タイムスタンプの種類 | 取得用のメソッド | 設定用のメソッド |
---|---|---|
作成日時 |
GetCreationTime
GetCreationTimeUtc |
SetCreationTime
SetCreationTimeUtc |
書き込み日時 |
GetLastWriteTime
GetLastWriteTimeUtc |
SetLastWriteTime
SetLastWriteTimeUtc |
アクセス日時 |
GetLastAccessTime
GetLastAccessTimeUtc |
SetLastAccessTime
SetLastAccessTimeUtc |
これらのメソッドではタイムスタンプをDateTime型で扱います。 タイムスタンプを整数値に変換したい場合はDateTime.ToFileTimeメソッドを使います。 また、UNIX時間に変換する方法についてはUNIX時間をDateTime型に変換するで解説しています。
末尾に〜UtcとついているメソッドではタイムスタンプをUTCでの日時で扱い、それ以外のメソッドではローカル時刻で扱います。 ローカル時刻・UTCについては時刻の種類・UTCとの時差・タイムゾーン間の変換を参照してください。
Monoの場合、UNIX環境ではGet/SetLastAccessTimeはatime(アクセス日時)、Get/SetLastWriteTimeはmtime(変更日時)を取得・設定します。 一方GetCreationTimeはGetLastWriteTimeと同じくmtimeを返しますが、SetCreationTimeの呼び出しでは何もしません。 また、Fileクラスのメソッドでは直接ctime(ステータス変更)の日時を取得・設定することはできません。
FileInfo・DirectoryInfo・DriveInfo
FileInfoクラスおよびDirectoryInfoクラスはファイル・ディレクトリを表すクラスです。 FileクラスやDirectoryクラスを使った操作では常に操作対象となるファイル・ディレクトリのパスを引数に必要としますが、FileInfoクラス・DirectoryInfoクラスではインスタンス自体がファイル・ディレクトリを表し、常にインスタンスがパスを保持していることになり、操作を行う都度パスを指定する必要がなくなります。 Fileクラス・Directoryクラスはインスタンスを作成せずに使用することができますが、FileInfoクラス・DirectoryInfoクラスを使う場合は常にインスタンスを作成する必要があります。
両者の違いを比較するために、FileクラスとFileInfoクラスを使ってファイルの存在確認とコピーを行う例を挙げるとつぎのようになります。
この例で使用しているExistsメソッドやCopyメソッド以外にも、Fileクラス・Directoryクラスに用意されているファイル・ディレクトリ操作のメソッドはFileInfoクラス・DirectoryInfoクラスにも用意されています。 そのため、どちらのクラスを使っても同じ操作が行えますが、操作を行う際にファイル名・ディレクトリ名を文字列として取り回すか、FileInfo・DirectoryInfoのインスタンスで取り回すかが異なるため、実装の都合に応じて使い分けることができます。
また、ドライブ情報を表すDriveInfoクラスも用意されています。 このクラスを使うと、システムに存在するドライブに関する情報(空き容量やドライブの種類、ルートディレクトリのパス)を取得することができます。 File・Directoryクラスとは異なり、DriveInfoクラスに対応するDriveのようなクラスは存在しないので、ドライブ情報を取得したい場合にはDriveInfoクラスを使う必要があります。
FileInfoクラス
FileInfoクラスはファイルを表すクラスです。 FileInfoクラスのインスタンスを作成する際はファイル名を含むパスを指定する必要がありますが、相対パス・絶対パスのどちらでも指定することもできます。 また、存在しないファイルのインスタンスも作成することができます。
FileInfoクラスのメソッド・プロパティとFileクラス・Pathクラスのメソッドの対応は次のとおりです。 FileInfoクラスのメソッド・プロパティの動作は、対応するFileクラス・Pathクラスのメソッドの動作と基本的には同じです。
操作 | FileInfoクラスのメンバ | 対応するFileクラス・Pathクラスのメソッド |
---|---|---|
コピー | CopyToメソッド | File.Copy |
移動・リネーム | MoveToメソッド | File.Move |
削除 | Deleteメソッド | File.Delete |
ファイルが存在するか | Existsプロパティ | File.Exists |
ファイルの作成 | Createメソッド | File.Create |
ファイルのオープン | Open/OpenRead/OpenWriteメソッド | File.Open/OpenRead/OpenWrite |
フルパスの取得 | FullNameプロパティ | Path.GetFullPath |
ディレクトリ名の取得 | DirectoryNameプロパティ | Path.GetDirectoryName |
ファイル名の取得 | Nameプロパティ | Path.GetFileName |
拡張子の取得 | Extensionプロパティ | Path.GetExtension |
ファイル属性の取得・設定 | Attributesプロパティ | File.GetAttributes/SetAttributes |
タイムスタンプの取得・設定 |
CreationTime/CreationTimeUtcプロパティ LastAccessTime/LastAccessTimeUtcプロパティ LastWriteTime/LastWriteTimeUtcプロパティ |
File.SetCreationTimeなど |
ファイルサイズの取得 | Lengthプロパティ | (なし) |
操作 | FileInfoクラスのメンバ | 対応するFileクラス・Pathクラスのメソッド |
DirectoryNameプロパティはディレクトリ名を文字列で取得することができますが、Directoryプロパティを参照するとファイルが配置されているディレクトリをDirectoryInfoで取得することができるようになっています。
DirectoryInfoクラス
DirectoryInfoクラスはディレクトリを表すクラスです。 FileInfoクラスと同様にDirectoryInfoクラスのインスタンスを作成する際はディレクトリ名を含むパスを指定する必要がありますが、相対パス・絶対パスのどちらでも指定することもできます。 また、存在しないディレクトリのインスタンスを作成することもできます。
DirectoryInfoクラスのメソッド・プロパティとDirectoryクラス・Pathクラスのメソッドの対応は次のとおりです。 DirectoryInfoクラスのメソッド・プロパティの動作は、対応するDirectoryクラス・Pathクラスのメソッドの動作と基本的には同じです。
操作 | DirectoryInfoクラスのメンバ | 対応するDirectoryクラス・Pathクラスのメソッド |
---|---|---|
作成 | Createメソッド | Directory.CreateDirectory |
サブディレクトリの作成 | CreateSubdirectoryメソッド | Directory.CreateDirectory |
移動・リネーム | MoveToメソッド | Directory.Move |
削除 | Deleteメソッド | Directory.Delete |
ディレクトリが存在するか | Existsプロパティ | Directory.Exists |
フルパスの取得 | FullNameプロパティ | Path.GetFullPath |
ディレクトリ名の取得 | Nameプロパティ | Path.GetDirectoryName |
タイムスタンプの取得・設定 |
CreationTime/CreationTimeUtcプロパティ LastAccessTime/LastAccessTimeUtcプロパティ LastWriteTime/LastWriteTimeUtcプロパティ |
Directory.SetCreationTimeなど |
操作 | DirectoryInfoクラスのメンバ | 対応するDirectoryクラス・Pathクラスのメソッド |
DirectoryInfoクラスでは、親ディレクトリのDirectoryInfoをParentプロパティ、ルートディレクトリのDirectoryInfoをRootプロパティでそれぞれ取得することができます。
DirectoryInfoクラスを使ったディレクトリの走査
DirectoryクラスのGetFiles・EnumerateFilesメソッドでは見つかったファイルの名前が文字列で返されますが、DirectoryInfoクラスのGetFiles・EnumerateFilesメソッドでは文字列ではなくFileInfoクラスが返されます。
同様にDirectoryInfoクラスのGetDirectories・EnumerateDirectoriesメソッドでは見つかったディレクトリはDirectoryInfoで返されます。 GetFileSystemInfos・EnumerateFileSystemInfosメソッドではFileSystemInfoで返されます。
FileSystemInfoクラス
FileSystemInfoクラスはGetFileSystemInfos・EnumerateFileSystemInfosメソッドの戻り値の型に使用されるクラスです。 このクラスはFileInfoクラスおよびDirectoryInfoクラスに共通する基底クラスです。 GetFileSystemInfos・EnumerateFileSystemInfosでは見つかったファイルのFileInfoおよびサブディレクトリのDirectoryInfoが返されます。
FileSystemInfoクラスにはファイルまたはディレクトリの名前を取得するNameプロパティ、フルパスを取得するFullNameプロパティ、実際に存在するかどうかを取得するExistsプロパティなどFileInfoクラスとDirectoryInfoクラスに共通するプロパティが用意されています。
DriveInfoクラス
DriveInfoクラスはシステムに存在する論理ドライブの情報を取得するためのクラスです。 コンストラクタでドライブ名を指定してインスタンスを作成するか、GetDrivesメソッドによって存在するすべての論理ドライブのDriveInfoを取得することができます。 DriveTypeプロパティを参照するとドライブの種類(光学ドライブ・固定ディスク・ネットワーク・リムーバブルデバイスなど)を取得することができます。
Linux上のMonoではドライブの代わりにマウントされているディレクトリが列挙されます。
DriveInfoクラスにはこの他にも、ボリュームラベルを取得するVolumeLabel、ファイルシステムの種類(NTFSなど)を文字列形式で返すDriveFormat、ドライブの容量を取得するTotalSize, TotalFreeSpace, AvailableFreeSpaceなどのプロパティがありますが、これらの値はいずれもドライブの準備ができていない場合(CDが挿入されていないなど)に取得しようとするとIOExceptionをスローします。 メディアが使用可能か・ドライブの準備ができているかを調べるにはIsReadyプロパティを参照します。
DriveInfoクラスには光学ドライブのトレー開閉、メディアの取り外し・接続を行ったりするような操作を行うメソッドは用意されていません。 そういった操作を行う例はCD-ROM・リムーバブルメディアを取り出すで紹介しています。