2009-09-02 172 views
2

我不知道我是否正确执行此操作或者如果我的逻辑正确。如何在遍历文件夹树时删除文件

我想下去一个文件夹结构删除超过一定天数的文件,这部分我已经正确实施,删除空文件夹。

所有这些都可以在一个循环中完成吗?
我该在哪里做文件夹删除?

我想删除最多3层或4层的空文件夹。

private static void TraverseTree(System.IO.DirectoryInfo folder, double days) 
    { 
     Stack<string> dirs = new Stack<string>(); 

     if (!folder.Exists) 
      throw new ArgumentException(); 

     dirs.Push(folder.FullName); 

     while (dirs.Count > 0) 
     { 
      string currentDir = dirs.Pop(); 
      string[] subDirs; 
      try 
      { 
       subDirs = System.IO.Directory.GetDirectories(currentDir); 
      } 
      // An UnauthorizedAccessException exception will be thrown if we do not have 
      // discovery permission on a folder or file. It may or may not be acceptable 
      // to ignore the exception and continue enumerating the remaining files and 
      // folders. It is also possible (but unlikely) that a DirectoryNotFound exception 
      // will be raised. This will happen if currentDir has been deleted by 
      // another application or thread after our call to Directory.Exists. The 
      // choice of which exceptions to catch depends entirely on the specific task 
      // you are intending to perform and also on how much you know with certainty 
      // about the systems on which this code will run. 
      catch (UnauthorizedAccessException e) 
      { 
       Console.WriteLine(e.Message); 
       continue; 
      } 
      catch (System.IO.DirectoryNotFoundException e) 
      { 
       Console.WriteLine(e.Message); 
       continue; 
      } 

      string[] files = null; 
      try 
      { 
       files = System.IO.Directory.GetFiles(currentDir); 
      } 
      catch (UnauthorizedAccessException e) 
      { 

       Console.WriteLine(e.Message); 
       continue; 
      } 
      catch (System.IO.DirectoryNotFoundException e) 
      { 
       Console.WriteLine(e.Message); 
       continue; 
      } 

      // Perform the required action on each file here. 
      // Modify this block to perform your required task. 
      foreach (string file in files) 
      { 
       try 
       { 
        // Perform whatever action is required in your scenario. 
        System.IO.FileInfo fi = new System.IO.FileInfo(file); 
        Console.WriteLine("{0}: {1}, {2}", fi.Name, fi.Length, fi.CreationTime); 

        // Delete old files 
        if (fi.LastWriteTime < DateTime.Now.AddDays(-days)) 
         fi.Delete(); 
       } 
       catch (System.IO.FileNotFoundException e) 
       { 
        // If file was deleted by a separate application 
        // or thread since the call to TraverseTree() 
        // then just continue. 
        Console.WriteLine(e.Message); 
        continue; 
       } 
      } 

      // Push the subdirectories onto the stack for traversal. 
      // This could also be done before handing the files. 
      foreach (string str in subDirs) 
       dirs.Push(str); 
     } 
    } 

代码来自MSDN

回答

5

递归方法可能会更干净。

private static void DeleteOldFilesAndFolders(string path) 
{ 
    foreach (string directory in System.IO.Directory.GetDirectories(path)) 
    { 
     DeleteOldFilesAndFolders(directory); 

     // If the directory is empty and old, delete it here. 
    } 

    foreach (string file in System.IO.Directory.GetFiles(path)) 
    { 
     // Check the file's age and delete it if it's old. 
    } 
} 
+0

给我一个递归的文件系统步行者,我会给你一个文件系统,将溢出你的堆栈。 – plinth 2009-09-02 19:35:41

+0

@plinth真的吗?你的文件系统有多深?你真的有文件深埋数百个文件夹? – 2009-09-02 19:50:04

+0

是的。如果你把你的堆栈设置为n,我会嵌入n + 1个文件夹,并给你一个“合理的”用例,说明为什么它是这样。多年前,我曾在Acrobat Catalog上工作过,我们必须防止这种情况发生。堆分配实施起来有点难,在资源耗尽时更难以耗尽,更容易陷入困境。这是现实世界中最好的解决方案? – plinth 2009-09-02 20:19:10

0

Here is a more general solution到它给你一个文件系统学步车实现非递归为IEnumerable的问题。

针对您的解决方案或许可以被实现为:

List<string> directoriesToDelete = new List<string>(); 
DirectoryWalker walker = new DirectoryWalker(@"C:\pathToSource\src", 
    dir => { 
     if (Directory.GetFileSystemEntries(dir).Length == 0) { 
      directoriesToDelete.Add(dir); 
      return false; 
     } 
     return true; 
    }, 
    file => { 
     if (FileIsTooOld(file)) { 
      return true; 
     } 
     return false; 
    } 
    ); 
foreach (string file in walker) 
    File.Delete(file); 
foreach (string dir in directoriesToDelete) 
    Directory.Delete(dir); 
3

东西,我注意到你的代码是,完全走在树结构中的几十个“机制”的行压倒的两行代码那实际上是做这项工作的。这使得阅读,理解,更改,调试和维护此代码变得困难。

这是我会做的。 (1)获取所有文件,(2)过滤器找到要删除的文件,(3)删除每个文件。因此,编写一个程序,在一个语句中执行每个程序。

对于第一个操作,我将上面的机制分解到它自己的函数中:一个实现IEnumerable的函数,它所做的所有工作是继续产生有关文件的信息。它没有什么与他们;它唯一的目的是继续吐出文件信息。

一旦你有了这个机制,那么你就可以开始在该序列的顶部写查询来获得第二个操作。然后第三个操作直接从第二个操作开始。

总之,你的程序的主线应该是这个样子:

var allFiles = TraverseFolder(folder); 
var filesToDelete = from file in allFiles where IsOld(file) select file; 
foreach(var fileToDelete in filesToDelete) Delete(fileToDelete); 

清楚了吗?

+0

+1是的,非常清楚。谢谢 – Picflight 2009-09-02 19:51:23

0

我增强John's solution,实施缺码,错误处理和检查:

/* Given a directory path and a datetime, 
* recursively delete all files and directories contained in such directory 
* (given directory included) that are younger than the given date. 
*/ 
private bool DeleteDirectoryTree(string dir, DateTime keepFilesYoungerThan) 
{ 
    //checks 
    if (String.IsNullOrEmpty(dir) || !Directory.Exists(dir)) 
     return false; 

    //recurse on children directories 
    foreach (string childDir in Directory.GetDirectories(dir)) 
     DeleteDirectoryTree(childDir, keepFilesYoungerThan); 

    //loop on children files 
    foreach (string file in Directory.GetFiles(dir)) 
    { 
     //calculate file datetime 
     DateTime fileDT = new DateTime(Math.Max(File.GetCreationTime(file).Ticks, File.GetLastWriteTime(file).Ticks)); 
     //if file is old, delete it 
     if (fileDT <= keepFilesYoungerThan) 
      try 
      { 
       File.Delete(file); 
       Log("Deleted file " + file); 
      } 
      catch (Exception e) 
      { 
       LogError("Could not delete file " + file + ", cause: " + e.Message); 
      } 
    } 

    //if this directory is empty, delete it 
    if (!Directory.EnumerateFileSystemEntries(dir).Any()) 
     try 
     { 
      Directory.Delete(dir); 
      Log("Deleted directory " + dir); 
     } 
     catch (Exception e) 
     { 
      LogError("Could not delete directory " + dir + ", cause: " + e.Message); 
     } 

    return true; 
}