【问题标题】:How to delete files while Traversing folder tree如何在遍历文件夹树时删除文件
【发布时间】:2010-11-25 01:44:09
【问题描述】:

我不确定我这样做是否正确,或者我的逻辑是否正确。

我正在尝试向下文件夹结构删除超过一定天数的文件,这部分我已经正确实现,删除空文件夹。

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

我想删除最多 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

【问题讨论】:

    标签: c# filesystems delete-file


    【解决方案1】:

    递归方法可能会更简洁。

    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.
        }
    }
    

    【讨论】:

    • 给我一个递归文件系统遍历器,我会给你一个会溢出你的堆栈的文件系统。
    • @plinth 真的吗?你的文件系统有多深?您真的将文件埋在数百个文件夹深处吗?
    • 确实如此。如果您将堆栈设置为 n,我将嵌入 n + 1 个文件夹,并为您提供一个“合理”的用例,说明为什么会这样。几年前,我在 Acrobat Catalog 上工作,我们不得不针对这种情况对其进行防弹。堆分配有点难以实现,更难以耗尽,并且在资源耗尽时更容易陷入困境。哪个是现实世界中最好的解决方案?
    • 您介意粘贴其中一个深度超过一百个文件夹的真实路径吗?我从来没有遇到过类似的事情。事实上,就在不久之前,在 Windows 中根本不可能有足够长的路径字符串。
    【解决方案2】:

    我注意到您的代码的一点是,用于遍历树结构的数十行“机制”完全压倒了实际完成工作的两行代码。这使得代码难以阅读、理解、更改、调试和维护。

    这就是我要做的。

    您的程序中只有三个高级操作:(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);
    

    清楚吗?

    【讨论】:

      【解决方案3】:

      这里几乎有同样的问题:

      How to delete all files and folders in a directory?

      这是按名称删除,但您可以检查其他属性。

      【讨论】:

      • 谢谢我在发布我的问题之前看过帖子。
      【解决方案4】:

      Here is a more general solution 给你一个文件系统walker 以非递归方式实现为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);
      

      【讨论】:

        【解决方案5】:

        我增强了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;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-01
          • 2011-03-25
          • 2010-10-09
          • 1970-01-01
          • 2018-01-16
          • 2019-05-08
          相关资源
          最近更新 更多