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

ファイルの列挙

あるフォルダ内に存在するファイルの一覧を取得するにはDirectory.GetFilesメソッドを使用します。


string path = @"C:\dir\";

//フォルダ内のすべてのファイルを取得
string[] allFiles = Directory.GetFiles(path);

foreach (var f in allFiles)
    Console.WriteLine(f);

Directory.GetFilesメソッドはstring型の配列を返します。
格納される文字列は指定のフォルダ内に存在するファイルの絶対パスです。

パターン指定(絞り込み検索)

Directory.GetFilesの第二引数にヒットする文字列のパターンを指定すると、検索対象の絞り込みができます。


//拡張子が「.txt」のファイルのみ取得
string[] allTxtFiles =
	Directory.GetFiles(path, "*.txt");

指定する文字列はワイルドカードを使用した文字列です。
「*」は任意の文字列、「?」は任意の一文字を表します。

ワイルドカード
ワイルドカードは文字列を柔軟に指定するための特殊文字です。
「?」は任意の一文字を意味します。
  • 200?年→「2001年」「200a年」などにヒット
「*」は任意の文字列を意味します。
0文字にもヒットします。
  • 2*年→「2年」「234年」「2abc年」などにヒット
  • *.txt→「abc.txt」「1234.txt」などにヒット
  • *.*→「abc.jpg」「1234.xml」などにヒット

サブフォルダ以下のファイルも取得

上記の方法で取得できるのは「指定のフォルダの直下に存在するファイル」です。
指定フォルダにさらにフォルダ(サブフォルダ)が存在する場合、その中身は取得されません。

サブフォルダ以下に存在するファイルも取得するにはDirectory.GetFilesの第三引数にSearchOption.AllDirectoriesを指定します。


//サブフォルダ内のファイルも含めて取得
string[] allFiles =
	Directory.GetFiles(path, "*", SearchOption.AllDirectories);

フォルダの列挙

あるフォルダ内に存在するフォルダの一覧を取得するにはDirectory.GetDirectoriesメソッドを使用します。


string path = @"C:\dir\";

//フォルダ内のすべてのフォルダを取得
string[] allDirectories = Directory.GetDirectories(path);

foreach (var f in allDirectories)
    Console.WriteLine(f);

Directory.GetDirectoriesメソッドはstring型の配列を返します。
格納される文字列は指定のフォルダ内に存在するフォルダの絶対パスです。

パターン指定(絞り込み検索)

Directory.GetDirectoriesの第二引数にヒットする文字列のパターンを指定すると、検索対象の絞り込みできます。


//名前に「○○tmp」のフォルダのみ取得
string[] tmpDirectories =
	Directory.GetDirectories(path, "*tmp");

指定する文字列はワイルドカードを使用した文字列です。
「*」は任意の文字列、「?」は任意の一文字を表します。

サブフォルダ以下のフォルダも取得

上記の方法で取得できるのは「指定のフォルダの直下に存在するフォルダ」です。
指定フォルダにさらにフォルダ(サブフォルダ)が存在していても取得できません。

サブフォルダ以下に存在するフォルダも取得するにはDirectory.GetDirectoriesの第三引数にSearchOption.AllDirectoriesを指定します。


//サブフォルダ内のファイルも含めて取得
string[] allDirectories =
	Directory.GetDirectories(path, "*", SearchOption.AllDirectories);

Directory.EnumerateFiles(EnumerateDirectories)

ファイルの一覧を取得するにはもうひとつ「Directory.EnumerateFiles」というメソッドがあります。
フォルダの列挙にも同様に「Directory.EnumerateDirectories」というメソッドがあります。
(いずれも.NET Framework4.0以降で使用可能)

これらのメソッドは、見つかったファイル(フォルダ)に対して一つずつ何らかの処理をする場合にメリットが(ある可能性が)あります。
Directory.GetFilesメソッドは指定のフォルダ内にあるファイルをすべて検索し終えてからファイルの一覧を返します。
つまり、すべてのファイルの取得が完了するまで処理が停止されます。
ファイル数が多い場合などはプログラムが停止したように見える場合があります。

それに対して「Directory.EnumerateFiles」は、ひとつファイルが見つかるたびにプログラムに処理を返します。
次のファイルは必要になったときに改めて取得します。
存在するファイルすべてを検索するまで待つ必要がないので、プログラムが停止したように見えることはありません。
(「Directory.EnumerateDirectories」も同様です)

これらのメソッドの戻り値は「IEnumerable<string>」という型になります。
これはforeach文で値を一つずつ取り出すことができます。
(取り出された値はstring型)


string path = @"C:\dir\";

//フォルダ内のファイルをサブフォルダも含めてすべて取得
IEnumerable<string> allFiles =
	Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories);

foreach (string f in allFiles)
    Console.WriteLine(f);

フォルダの削除

フォルダの削除にはDirectory.Deleteメソッドを使用しますが、フォルダ内に読み取り専用属性のファイルが含まれると削除できません。
読み取り専用ファイルが含まれるフォルダを削除するには、ファイルを列挙し、ファイルの読み取り専用属性を解除してから削除する必要があります。


string path = @"C:\dir\";

string[] allFiles = Directory.GetFiles(path, "*", SearchOption.AllDirectories);

foreach (string f in allFiles)
{
    FileAttributes attr = File.GetAttributes(f);

    //ReadOnly属性が設定されている場合は外す
    if ((attr & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
    {
        File.SetAttributes(f, attr & ~FileAttributes.ReadOnly);
    }
}

//フォルダ削除
Directory.Delete(path, true);

フォルダのコピー

Dictionaryクラスにはフォルダをコピーするメソッドは用意されていないので、ファイルとフォルダの列挙を利用して自分で処理を書く必要があります。
ここではその例を示します。


/// <summary>
/// フォルダをコピーする
/// </summary>
/// <param name="sourceDir">コピー元フォルダ</param>
/// <param name="destDir">コピー先フォルダ</param>
/// <returns>sourceDirが存在しなければ偽</returns>
static bool CopyDirectory(string sourceDir, string destDir)
{
    //コピー元フォルダがなければ終了
    if (!Directory.Exists(sourceDir))
        return false;

    //コピー先フォルダが存在しない場合は作成
    if(!Directory.Exists(destDir))
    {
        Directory.CreateDirectory(destDir);

        //属性のコピー
        File.SetAttributes(destDir, File.GetAttributes(sourceDir));
    }
    //コピー先フォルダが存在するが
    //属性が異なる場合は属性コピー
    else if(File.GetAttributes(sourceDir) != File.GetAttributes(destDir))
    {
        File.SetAttributes(destDir, File.GetAttributes(sourceDir));
    }

    string[] files = Directory.GetFiles(sourceDir);
    foreach(var file in files)
    {
        //コピー先のパスを作成
        string pathDest = Path.Combine(destDir, Path.GetFileName(file));

        //コピー先にファイルが存在し、
        //読み取り専用属性が設定されている場合は解除する
        if (File.Exists(pathDest) &&
            (File.GetAttributes(pathDest) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly
            )
        {
            File.SetAttributes(pathDest, File.GetAttributes(pathDest) & ~FileAttributes.ReadOnly);
        }

        //ファイルコピー
        //ファイルが存在する場合は上書き
        File.Copy(file, pathDest, true);
    }

    string[] dirs = Directory.GetDirectories(sourceDir);
    foreach (var dir in dirs)
    {
    	//再帰呼び出し
        //コピー元フォルダ内のサブフォルダをコピー
        CopyDirectory(dir, Path.Combine(destDir, Path.GetFileName(dir)));
    }
    return true;
}

static void Main(string[] args)
{
    string pathSource = @"C:\Test";
    string pathDest = @"C:\Test_Copy";

    if (CopyDirectory(pathSource, pathDest))
        Console.WriteLine("{0}を{1}にコピーしました。", pathSource, pathDest);
    else
        Console.WriteLine("{0}が見つかりません。", pathSource);

    Console.ReadLine();
}