共用方式為


HOW TO:使用 PLINQ 逐一查看檔案目錄

更新:2010 年 5 月

這個範例示範在檔案目錄上平行處理作業的兩個簡單方式。 第一個查詢使用 GetFiles 方法,在目錄和所有子目錄中填入檔案名稱的陣列。 這個方法等到填入整個陣列之後才會傳回,因此會在作業開頭時引入延遲。 不過,在填入陣列之後,PLINQ 就會平行、非常快速地處理它。

第二個查詢使用靜態 EnumerateDirectoriesEnumerateFiles 方法,立即開始傳回結果。 這個作法在逐一查看大型目錄樹狀結構時比較快,儘管處理時間相較於第一個範例可能會根據許多因素而不同。

注意事項警告

這些範例是為了示範用法,執行速度可能比不上對應的循序 LINQ to Objects 查詢。如需加速的詳細資訊,請參閱認識 PLINQ 中的加速

範例

下列範例示範當您能存取樹狀結構中的所有目錄、檔案大小不是太大、存取時間也不是太多的簡單情況下,如何逐一查看檔案目錄。 這個作法在一開始建構檔案名稱的陣列時有一段延遲。


struct FileResult
{
    public string Text;
    public string FileName;
}
// Use Directory.GetFiles to get the source sequence of file names.
public static void FileIteration_1(string path)
{       
    var sw = Stopwatch.StartNew();
    int count = 0;
    string[] files = null;
    try
    {
        files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
    }
    catch (UnauthorizedAccessException e)
    {
        Console.WriteLine("You do not have permission to access one or more folders in this directory tree.");
        return;
    }

    catch (FileNotFoundException)
    {
        Console.WriteLine("The specified directory {0} was not found.", path);
    }

    var fileContents = from file in files.AsParallel()
            let extension = Path.GetExtension(file)
            where extension == ".txt" || extension == ".htm"
            let text = File.ReadAllText(file)
            select new FileResult { Text = text , FileName = file }; //Or ReadAllBytes, ReadAllLines, etc.              

    try
    {
        foreach (var item in fileContents)
        {
            Console.WriteLine(Path.GetFileName(item.FileName) + ":" + item.Text.Length);
            count++;
        }
    }
    catch (AggregateException ae)
    {
        ae.Handle((ex) =>
            {
                if (ex is UnauthorizedAccessException)
                {
                   Console.WriteLine(ex.Message);
                   return true;
                }
                return false;
            });
    }

    Console.WriteLine("FileIteration_1 processed {0} files in {1} milliseconds", count, sw.ElapsedMilliseconds);
    }

下列範例示範當您能存取樹狀結構中的所有目錄、檔案大小不是太大、存取時間也不是太多的簡單情況下,如何逐一查看檔案目錄。 這個作法比前一個作法更快開始產生結果。


struct FileResult
{
    public string Text;
    public string FileName;
}

// Use Directory.EnumerateDirectories and EnumerateFiles to get the source sequence of file names.
public static void FileIteration_2(string path) //225512 ms
{
    var count = 0;
    var sw = Stopwatch.StartNew();
    var fileNames = from dir in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories)
                    select dir;


    var fileContents = from file in fileNames.AsParallel() // Use AsOrdered to preserve source ordering
                       let extension = Path.GetExtension(file)
                       where extension == ".txt" || extension == ".htm"
                       let Text = File.ReadAllText(file)
                       select new { Text, FileName = file }; //Or ReadAllBytes, ReadAllLines, etc.
    try
    {
        foreach (var item in fileContents)
        {
            Console.WriteLine(Path.GetFileName(item.FileName) + ":" + item.Text.Length);
            count++;
        }
    }
    catch (AggregateException ae)
    {
        ae.Handle((ex) =>
            {
                if (ex is UnauthorizedAccessException)
                {
                   Console.WriteLine(ex.Message);
                   return true;
                }
                return false;
            });
    }

    Console.WriteLine("FileIteration_2 processed {0} files in {1} milliseconds", count, sw.ElapsedMilliseconds);
}

使用 GetFiles 時,確認您擁有樹狀結構中所有目錄足夠的使用權限。 否則會擲回例外狀況,也不會傳回結果。 在 PLINQ 查詢中使用 EnumerateDirectories 時,以非失誤性、能繼續逐一查看的方式處理 I/O 例外狀況時會有問題。 如果您的程式碼必須處理 I/O 或未授權的存取例外狀況,應該考慮 HOW TO:使用平行類別逐一查看檔案目錄中說明的作法。

如果 I/O 延遲是問題,例如在網路上處理檔案 I/O 時,請考慮使用 TPL 和傳統 .NET 非同步程式設計和此部落格文章 (英文) 中說明的其中一個非同步 I/O 技巧。

請參閱

概念

平行 LINQ (PLINQ)

變更記錄

日期

記錄

原因

2010 年 5 月

加入有關使用方式和 加速的比較注意事項。

客戶回函。