我有這個功能,它應該從給定的根目錄和檔案名中找到完整的檔案名。
static string WalkDirectoryTree(DirectoryInfo root, string fileName)
{
FileInfo[] files = null;
DirectoryInfo[] subDirs = null;
files = root.GetFiles("*.*");
string fullFileName = "";
string rnd = "";
if (files != null)
{
foreach (FileInfo file in files)
{
if(file.Name == fileName)
{
Console.WriteLine("Success!");
fullFileName = file.FullName;
rnd = file.Name;
return fullFileName;
}
}
subDirs = root.GetDirectories();
foreach (DirectoryInfo dirInfo in subDirs)
{
if (rnd == fileName)
{
break;
}
else
{
WalkDirectoryTree(dirInfo, fileName);
}
}
}
return fullFileName;
}
我正在查看這段代碼如何在斷點的幫助下執行。它找到搜索到的檔案名并輸入 if 陳述句(如下)
if(file.Name == fileName)
{
Console.WriteLine("Success!");
fullFileName = file.FullName;
rnd = file.Name;
return fullFileName;
}
通過跟隨執行我還發現,它確實執行了上面 if 陳述句中的回傳步驟,然后直接到函式的末尾,但是,它繼續一次又一次地執行該函式,直到它消失通過給定根目錄中的所有子目錄。顯然,它覆寫了回傳值,這不是這個函式的目的。
有人可以發現問題并提出任何解決方案嗎?
uj5u.com熱心網友回復:
正如其他人所指出的那樣,您正在呼叫一個遞回函式,因此您會收到很多呼叫,WalkDirectoryTree并且每個呼叫都回傳一個且只有一個值,但是由于呼叫很多,看起來一個呼叫仍在進行。
我確實想給你一個替代方案,它可能會為你提供一些關于未來如何解決這類問題的思考。
您遞回的關鍵是遍歷您的目錄結構。如果您從一種方法開始。
static IEnumerable<DirectoryInfo> WalkDirectoryTree(DirectoryInfo root)
{
yield return root;
foreach (var di1 in root.GetDirectories())
foreach (var di2 in WalkDirectoryTree(di1))
yield return di2;
}
這只是回傳所有以目錄結構開頭root并向下遞回的目錄,直到它用完目錄。它被懶惰地評估,所以它只回傳你要求的盡可能多的目錄。這在您查找檔案時很有用,因為一旦找到您的檔案,它將停止列出目錄。
現在搜索功能很簡單且非遞回。
static string FindTheFile(DirectoryInfo root, string fileName)
{
foreach (var di in WalkDirectoryTree(root))
foreach (var fi in di.GetFiles())
if (fi.Name == fileName)
return fi.FullName;
return String.Empty;
}
我希望這有幫助。
uj5u.com熱心網友回復:
恭喜,您發現了一個樹遍歷問題,顯式堆疊可能比遞回函式呼叫更好地解決這個問題。
雖然可以檢查遞回呼叫的回傳值,正如一些人所評論的那樣,但有一個與之相關的價格。這是一個更好的選擇:
static string WalkDirectoryTree(DirectoryInfo root, string fileName)
{
var to_process = new Stack<DirectoryInfo>();
to_process.Push(root);
while (to_process.TryPop(out var dir))
{
foreach (FileInfo file in dir.GetFiles(filename))
{
if(file.Name == fileName)
{
Console.WriteLine("Success!");
return file.FullName;
}
}
foreach (DirectoryInfo subdir in dir.GetDirectories())
{
to_process.Push(subdir);
}
}
return null; // no matches
}
這將像遞回版本一樣進行深度優先搜索,但它不會在呼叫堆疊上使用多個幀,因此第一個匹配項可以立即回傳給原始呼叫者,而遞回版本回傳給自身上一級目錄. GetDirectories()請注意,由于使用 LIFO 堆疊,搜索將按照與回傳子目錄相反的順序進行……如果重要的話,可以通過GetDirectories()在回圈和推送之前反轉結果來更改。
我還更改了傳遞給dir.GetFilesfrom *.*to的 filespec filename,因為您對目錄中的所有檔案都不感興趣。我沒有取出區分大小寫的字串相等性測驗,但您可能也不希望這樣做。
盡管如此,學習撰寫和除錯遞回代碼還是一個好主意。在除錯器中單步執行時,請確保打開“呼叫堆疊”除錯器視窗,并在點擊return陳述句時仔細觀察呼叫堆疊視窗。
最后,這個遞回搜索被內置到框架中。簡單地
return root.EnumerateFiles(fileName, SearchOption.AllDirectories).FirstOrDefault();
足以執行在第一個匹配項處停止的遞回搜索(不像傳遞相同SearchOption.AllDirectories的GetFiles()內容會浪費地找到整個目錄樹中的每個匹配項)
Really, the only reason for writing this yourself, apart from the experience gained, is to avoid the pitfall mentioned in the documentation:
If you choose
AllDirectoriesin your search and the directory structure contains a link that creates a loop, the search operation enters an infinite loop.
When writing the tree walk yourself, it's possible to do something about this problem (although the improved code presented above still ignores this situation)
uj5u.com熱心網友回復:
問題出在您對WalktDirecotryTree. 你不檢查它的回傳值,所以如果回傳你想要的,你需要保釋。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/452585.html
上一篇:C#泛型方法引數
