【发布时间】:2016-12-13 06:35:53
【问题描述】:
我目前正在编写一个程序,该程序可以使用用户给定的参数从各种来源大量下载图像。
我的问题是我不希望发生重复。 我应该指出,我正在处理一次最多 100 个的大量下载(不是那么大),并且每个文件都有不同的名称,所以简单地按文件名搜索是行不通的,我需要检查哈希值。
无论如何,这是我已经找到的:
Directory.GetFiles(FullPath)
.Select(f => new
{
FileName = f,
FileHash = Encoding.UTF8.GetString(new SHA1Managed().ComputeHash(new FileStream(f, FileMode.Open, FileAccess.Read)))
})
.GroupBy(f => f.FileHash)
.Select(g => new { FileHash = g.Key, Files = g.Select(z => z.FileName).ToList() })
.SelectMany(f => f.Files.Skip(1))
.ToList()
.ForEach(File.Delete);
我的问题是,在“File.Delete”行,我得到了一个非常著名的错误,即该文件已被另一个进程使用。我认为这是因为上面的代码缺少在删除文件之前关闭它用来获取 FileHash 的 FileStream 的方法,但我不知道如何解决这个问题,有什么想法吗?
我还应该指出我已经尝试过其他解决方案,比如这个(没有 linq):https://www.bhalash.com/archives/13544802709 用删除的替换打印功能,没有错误但不起作用。
提前致谢,我随时为您提供所需的任何其他信息! :)
秋竹
【问题讨论】:
-
啊,一个班轮的奇迹就可以做到这一切......
-
对于任何偶然发现这个老问题的人,除了下面的优秀答案之外,我想补充一点,上面的代码有一些不必要的低效率。
ToList调用会增加很多不必要的开销,FileHash的第二个定义是完全没有必要的,因为它以后再也不会使用了。因此GroupBy之后的行可以用更简单的.Select(g => g.Select(z => z.FileName)).SelectMany(f => f.Skip(1))替换,第二个ToList调用可以通过将整个语句放在foreach 循环中并在foreach 主体内调用File.Delete来消除。
标签: c# linq file directory duplicates