HOW TO:使用 PLINQ 逐一查看檔案目錄
更新:2010 年 5 月
這個範例示範在檔案目錄上平行處理作業的兩個簡單方式。 第一個查詢使用 GetFiles 方法,在目錄和所有子目錄中填入檔案名稱的陣列。 這個方法等到填入整個陣列之後才會傳回,因此會在作業開頭時引入延遲。 不過,在填入陣列之後,PLINQ 就會平行、非常快速地處理它。
第二個查詢使用靜態 EnumerateDirectories 和 EnumerateFiles 方法,立即開始傳回結果。 這個作法在逐一查看大型目錄樹狀結構時比較快,儘管處理時間相較於第一個範例可能會根據許多因素而不同。
警告 |
---|
這些範例是為了示範用法,執行速度可能比不上對應的循序 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 技巧。
請參閱
概念
變更記錄
日期 |
記錄 |
原因 |
---|---|---|
2010 年 5 月 |
加入有關使用方式和 加速的比較注意事項。 |
客戶回函。 |