2011-11-26 76 views
2

我需要寫在C#代碼將從數據表中選擇文件名列表,這是此列表中的文件夾中刪除所有文件。刪除不在數據表中的文件的最快方法?

一種可能性是按名稱排序,然後遍歷我的表結果,對於每個結果循環遍歷我的文件並刪除它們,直到找到與當前結果相匹配的文件或字母更大,然後移動到下一個結果而不重置當前文件索引。

我還沒有試過真正實現這一點,但在我看來,這將是一個爲O​​(n),因爲每個列表將通過被環只有一次(忽略排序兩個列表部分)。我不知道的唯一情況是我能否100%確定文件系統和數據庫引擎的排序方式完全相同(他們都認爲「_」小於「 - 」之類的東西)。如果不是,上面的算法根本不起作用。 (順便說一下,這是一個Jet引擎數據庫。)

但由於這可能不是這樣的罕見問題你們可能已經知道一個更好的解決方案。我試圖搜索網頁,但找不到任何東西。也許更有效的解決方案是將每個列表放入一個HashSet並找出它們的區別。

回答

2
  1. 獲取該文件夾的內容爲folderFilesIEnumerable<string>
  2. 得到你想要保持filesToKeepIEnumerable<string>
  3. 獲取的「不在列表中的」文件列表中的文件。
  4. 刪除這些文件。

代碼示例:

IEnumerable<FileInfo> folderFiles = new List<FileInfo>(); // Fill me. 
IEnumerable<string> filesToKeep = new List<string>();  // Fill me. 
foreach (string fileToDelete in folderFiles.Select(fi => fi.FullName).Except(filesToKeep)) 
{ 
    File.Delete(fileToDelete); 
} 
+0

我正準備寫一個非常類似的解決方案,但使用'HashSet.ExceptWith'代替。我不確定'IEnumerable.Except'和'HashSet.ExceptWith'一樣快。另一方面,你的代碼不涉及填充'HashSet'。 – Juan

+0

如果你想要刪除很多文件(比如很多文件!),hashset方式可能會更有效率,但這只是推測。我其實認爲「刪除」操作將成爲瓶頸。即使你使用多線程,硬件也會是我想的限制。 – Tipx

1

這是我給你的建議。假設filesInDatabase包含在數據庫和pathOfDirectory包含的目錄中的文件進行比較包含的路徑文件列表。

foreach (var fileToDelete in Directory.EnumerateFiles(pathOfDirectory).Where(item => !filesInDatabase.Contains(item)) 
{ 
    File.Delete(fileToDelete); 
} 

編輯:

這需要using System.Linq;,因爲它使用LINQ。

+0

爲什麼你需要使用LINQ做這個的原因嗎?效率高嗎 – lloydom

+0

這需要O(n^2)。您爲第一個列表中的每個元素調用「Contains」。包含遍歷整個(第二個)列表。 – Neowizard

1

我覺得散列是要走的路,但你並不真的需要兩個HashSets。只需要一個HashSet來存儲數據表中的標準化文件名;另一個容器可以是任何收集數據類型。

+0

對於'O(n log(n))'+1。比'O(n^2)'更好,並且排序解決方案最終仍然是'n log(n)+ n'。這可能是最好的答案。 – kelloti

1

首先,.Net允許您定義可用於排序的文化,但我並不是那麼熟悉該機制,所以我會讓Google給出關於該主題的指示。其次,爲了避免所有的文化質量,你可以使用一個類似於基數排序(只有沒有排序)的思想的不同算法 - 時間複雜度是O(n * length_longest_file_name)。文件名的長度是有限的(據我所知,幾乎沒有文件系統會允許文件名超過256),所以我假設n比文件名長度大得多,如果n小於那麼最大文件名稱長度,只需使用O(n^2)方法並避免工作(反覆列出這個小小的值幾乎是即時時間)。 注意:此方法不需要排序。

這個想法是創建一個符號數組,可以用作文件名字符(大約60-70個字符,如果這是一個區分大小寫的搜索),另一個標誌數組與第一個字符陣列。 現在,您將爲DB中列表的文件名(從1 - > length_longest_file_name)爲每個char創建一個循環。 在每次迭代中(i)您都會查看數據庫列表中每個文件名的第i個字符。您看到的每個字符都會將相關標誌設置爲true。 設置了所有標誌後,您將遍歷第二個列表並刪除每個文件,該文件的第i個字符的名稱未被標記。

實現可能很複雜,當n很小時,兩個數組的開銷可能會變慢,但是您可以優化它以使其更好(例如,不會遍歷名稱短於當前i的文件通過從兩個列表中刪除它們)。

希望這可以幫助

0

我有另一種想法可能會更快。

var filesToDelete = new List<string>(Directory.GetFiles(directoryPath)); 
foreach (var databaseFile in databaseFileList) 
{ 
    filesToDelete.Remove(databaseFile); 
} 
foreach (var fileToDelete in filesToDelete) 
{ 
    File.Delete(fileToDelete); 
} 

說明:首先獲取目錄中包含的所有文件。然後從該列表中刪除數據庫中的每個文件。最後從列表filesToDelete中刪除所有剩餘的文件。

+0

'Remove'是一個O(n)方法(http://msdn.microsoft.com/en-us/library/cd666k3e.aspx),所以這將是O(n^2)。但是如果使用'HashSet'而不是'List',你的代碼應該變成O(n)。 – Juan

相關問題