2010-01-14 78 views
6

確定最大文件大小是最好的選擇,我寫了下面的方法來確定最大文件大小:是遞歸的目錄

public static long GetMaxFileSize(string dirPath, long maxFileSize) 
    { 
     DirectoryInfo [] dirInfos = new DirectoryInfo(dirPath).GetDirectories(); 
     foreach (DirectoryInfo dirInfo in dirInfos) 
     { 
      DirectoryInfo [] subDirInfos = dirInfo.GetDirectories(); 
      foreach (DirectoryInfo subDirInfo in subDirInfos) 
       maxFileSize = GetMaxFileSize(dirInfo.FullName, maxFileSize); 

      FileInfo [] fileInfos = dirInfo.GetFiles(); 
      foreach (FileInfo fileInfo in fileInfos) 
      { 
       if (maxFileSize < fileInfo.Length) 
        maxFileSize = fileInfo.Length; 
      } 
     } 

     return maxFileSize; 
    } 

Code Complete建議「使用遞歸選擇性」。既然如此,我想知道社區是否認爲這是對遞歸的有效使用。如果沒有,是否有更好的方法來做到這一點?

編輯:我不能在.NET 2.0中使用LINQ,因爲它不可用,但我不希望這個標籤,因爲只有進一步討論點像Jared的下方NET 2.0的問題。

編輯:根據在沒有獲取根目錄的文件時發現的問題清理代碼。

public static long GetMaxFileSize(DirectoryInfo dirInfo, long maxFileSize) 
    { 
     DirectoryInfo [] subDirInfos = dirInfo.GetDirectories(); 
     foreach (DirectoryInfo subDirInfo in subDirInfos) 
     { 
      maxFileSize = GetMaxFileSize(subDirInfo, maxFileSize); 
     } 

     FileInfo [] fileInfos = dirInfo.GetFiles(); 
     foreach (FileInfo fileInfo in fileInfos) 
     { 
      if (maxFileSize < fileInfo.Length) 
       maxFileSize = fileInfo.Length; 
     } 

     return maxFileSize; 
    } 
+1

你如何處理結和「快捷鍵」(硬或符號鏈接)?目錄樹並不總是一棵樹... – lexu

+0

我不確定這是*主觀*。一旦我們確定了「最佳選項」(最快,最小內存佔用或其他)的含義,那麼任何特定的解決方案都可以輕鬆測試。有*目標*標籤嗎?出於興趣 - 「最佳選擇」是什麼意思? –

+0

我不知道我是否應該將其標記爲主觀,但我會刪除它,除非有人反對。通過最佳選擇,我意味着最優雅和可靠的解決方案。我不確定是否有更安全的技術可以減少所需的代碼量。 –

回答

10

我認爲更好的辦法是將文件系統API通過Directory.GetFiles做搜索你。此方法提供了自動搜索子目錄。這消除了是否要遞歸的問題,而是留下了如何實現它的API(誰可能設計它這樣的場景)的設計師決定。

此方法與LINQ結合提供了一個非常簡潔的解決方案

var max = Directory 
    .GetFiles(path, "*", SearchOption.AllDirectories) 
    .Select(x => new FileInfo(x)) 
    .Select(x => x.Length) 
    .Max(); 

EDIT如麥指出的那樣,爲4.0或更高,最好使用EnumerateFiles以避免產生潛在的大陣列

的開銷
var max = Directory 
    .EnumerateFiles(path, "*", SearchOption.AllDirectories) 
    .Select(x => new FileInfo(x)) 
    .Select(x => x.Length) 
    .Max(); 
+0

我想知道是否有這樣的事情。不幸的是我在.NET 2.0中,並沒有這個選項可用。爲那些使用.NET 3.0或更高版本的用戶推薦。 –

+0

這顯然是一個非常優雅的功能解決方案,但是如果性能是一個考慮因素,這個價格如何? – ChaosPandion

+0

因爲您只查詢一次文件系統API,所以我會想象得更快。 – Jimmy

4

就樹遍歷而言,我認爲遞歸是非常適合的。 (目錄結構是一棵樹)

只要你知道目錄結構不是令人難以置信的巨大,你不應該擔心溢出堆棧。

遞歸解決方案導航樹幾乎總是比迭代解決方案

更優雅
+1

目錄結構往往是一棵樹,但不必是硬鏈接(或軟鏈接,如果你正在關注他們)意味着你可以訪問相同的文件不止一次,甚至有一個週期,如果操作系統允許硬鏈接到目錄 –

0

遞歸只應在特定的數據結構中。作爲樹結構的文件系統絕對是遞歸的好例子。我甚至會說,這可能是完成你想要做的事情的最好方法。

0

有關在堆棧大小上使用「有選擇地遞歸」的建議。在大容量的容器上,您可以溢出堆棧並導致代碼崩潰。

您遇到的問題將是包含65536或更多文件夾的大型目錄。

我發現Windows XP 32位與64k遞歸調用崩潰。

1

它看起來完全合理的對我說:有一個例外,你的方法將下降的深度是由文件系統,這是保證是有限的深度爲界。

唯一的例外是,如果它運行的文件系統有符號鏈接,你可以點擊一個鏈接到一個目錄這是你開始在一個的祖先,從而進入死循環,所以你需要考慮

  • 將您的應用部署這樣的文件系統(通常是類Unix,但我認爲Vista和Win7都支持)
  • 你想忽略符號鏈接
  • 做你的想要爲該方法追加一個額外的參數,該方法是先前輸入的直接的列表里斯。

在您的實現然而,你一直忽略在當前目錄下的文件,因此給出一個文件系統

DirA 
| 
+-DirB 
| | 
| +- DirC 
| +- DirD 
| | | 
| | +-DirE 
| | 
| +- DirF 
| 
+- DirG 

和路徑DIRA,你考慮到,僅僅是DIRB,DirG和可怕

你需要做的GetFiles()在當前目錄下,然後GetDirectories在當前目錄下,並得到各那些大小。默認情況下讓你的方法獲得一個DirInfo對象可能是有意義的,並且使用一個包含String的包裝器來重載它。

+0

有效的點。在進一步的檢查中,我會錯過根目錄文件。我會相應地改變它。 順便說一句,你怎麼會忽略符號鏈接? –

+0

符號鏈接不應太硬,你可以告訴一個符號鏈接,鏈接的事物之間的區別,只是不遵循符號鏈接。如果操作系統允許硬盤上的隨機硬鏈接,儘管你可能會遇到痛苦的世界 –