代码之家  ›  专栏  ›  技术社区  ›  Chaddeus

删除不在数组中的所有文件的C例程看起来是否正常?

  •  2
  • Chaddeus  · 技术社区  · 14 年前

    我有一个包含文件路径列表的数据库。我想构建一个清理文件夹的例程,如果没有数据库记录,就删除目录中的文件(对于临时Ajax文件上载,如果用户没有完成表单,等等)。

    我想是这样的:

    var dbFiles = db.allPaths();
    var allFiles = Directory.EnumerateFiles(path);
    
    foreach (var f in allFiles) {
      if (!dbFiles.Contains(f) {
        File.Delete(f);
      }
    }
    

    有人在等我吗?该程序将被设置为一周运行一次,如果临时文件出现问题,则运行频率会更高。它将在几乎没有用户的情况下运行,因此性能(尽管很重要)并不重要。

    更新

    哇,答案很多。这段代码正在变成值得分享的东西。我上面的代码只是一个简单、快速的占位符位…但它已经转变成了坚实的代码。谢谢您!

    4 回复  |  直到 9 年前
        1
  •  1
  •   Gabe Timothy Khouri    14 年前

    将所有建议合并为一个建议:

    // canonicalize paths
    var dbFiles = db.allPaths().Select(Path.GetFullPath);
    var allFiles = Directory.EnumerateFiles(Path.GetFullPath(path))
    
    foreach (var file in allFiles.Except(dbFiles, StringComparer.OrdinalIgnoreCase))
    {
        try {
            File.Delete(file);
        } catch (IOException) {
            // handle exception here
        }
    }
    
        2
  •  8
  •   Jon Skeet    14 年前

    看起来不错,但你可以简化:

    foreach (var file in allFiles.Except(dbFiles))
    {
        File.Delete(file);
    }
    

    你必须确保路径在 确切地 但格式相同。如果一个列表有相对文件,另一个列表有绝对文件,或者如果一个列表使用“/”,而另一个列表使用“”,则最终会删除不希望删除的内容。

    理想情况下,您应该先显式地规范化这些文件,但我看不到在.NET中获取规范文件名的好方法…

    编辑:注意 Path.GetFullPath 规范化。它修复了斜杠并使其成为绝对值,但它并没有解决这种情况:“c:/users”变为“c:\users”,“c:/users”变为“c:\users”。

    可以通过在调用中使用字符串比较器修复此问题。 Except :

    var dbFiles = db.AllPaths().Select(Path.GetFullPath));
    var allFiles = Directory.EnumerateFiles(path).Select(Path.GetFullPath));
    
    foreach (var file in allFiles.Except(dbFiles, StringComparer.OrdinalIgnoreCase))
    {
        File.Delete(file);
    }
    

    现在这忽略了案例——但以一种“有序”的方式。我不知道什么是Windows文件系统 真正地 就大小写敏感度而言。

        3
  •  3
  •   Jeffrey Kern    14 年前

    我觉得不错,但是我从来没有删除过C中的文件,只有vb。 但是,您可能希望将其放入try/catch循环,就好像无法删除文件(只读、当前正在使用、不再存在等),它将引发异常。

    编辑:路径是如何存储的?记住,在c中,你需要避开路径“//”,而不是使用“IIRC”。

    编辑2:抓取上次编辑的lol。

        4
  •  1
  •   Reinderien    14 年前

    我认为这在精神上是可以的,尽管它更接近:

    List<string> dbFiles = db.allPaths();
    string[] allFiles = Directory.GetFiles(path);
    
    foreach (string f in allFiles)
        if (!dbFiles.Contains(f))
            File.Delete(f);