2

我有一个包含文件路径列表的数据库。我想建立一个例程来清理文件夹,如果没有 db 记录,则删除目录中的文件(对于临时 ajax 文件上传,在用户未填写表单的情况下,等等......)。

我在想这样的事情:

var dbFiles = db.allPaths();
var allFiles = Directory.EnumerateFiles(path);

foreach (var f in allFiles) {
  if (!dbFiles.Contains(f) {
    File.Delete(f);
  }
}

有什么“陷阱”等着我吗?该例程最初将设置为每周运行一次,如果临时文件成为问题,则更频繁。它将在几乎没有用户使用的时候运行,因此性能(虽然很重要)并不是最重要的。

更新

哇,很多很棒的答案。这段代码正在变成值得“分享”的东西。;D 我上面的代码只是一个简单、快速的占位符位......但它已转换为可靠的代码。谢谢!

4

4 回答 4

8

看起来不错,但你可以让它更简单:

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 文件系统在区分大小写方面真正做了什么。

于 2010-06-22T06:17:21.903 回答
3

对我来说看上去很好; 但是我从来没有在 C# 中删除过文件,只是在 VB 中。但是,您可能希望将其放入 Try/Catch 循环中,就好像文件无法删除(只读、当前正在使用、不再存在等)一样,它会抛出异常。

编辑:路径是如何存储的?请记住,在 C# 中,您需要转义路径“//”而不是使用“\”IIRC。

编辑 2:从最后一次编辑出来大声笑。

于 2010-06-22T06:11:04.197 回答
1

我认为精神上没问题,尽管它更接近于:

List<string> dbFiles = db.allPaths();
string[] allFiles = Directory.GetFiles(path);

foreach (string f in allFiles)
    if (!dbFiles.Contains(f))
        File.Delete(f);
于 2010-06-22T06:18:20.980 回答
1

将所有建议合二为一:

// 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
    }
}
于 2010-06-22T06:36:21.883 回答