我有一个(似乎是什么)手头的大任务 我需要浏览多个文件夹的不同存档卷(我们正在谈论数TB的数据)。每个文件夹中都有一个.pst文件。其中一些文件夹(以及文件)可能完全相同(文件中的名称或数据)。我希望能够一次比较2个以上的文件(如果可能的话),看看是否找到了任何dulpicates。 找到重复项后,我需要删除它们并保留原件,然后最终提取所有唯一的电子邮件。
我知道有些程序可以找到重复项,但我不确定他们需要传递哪些参数这些文件,我不知道他们是否可以处理如此大量的数据。 我想用C#或VB编程。我不知道应该从哪里开始。有什么建议??
...防爆
m:\mail\name1\name.pst
m:\mail\name2\name.pst (same exact data as the one above)
m:\mail\name3\anothername.pst (duplicate file to the other 2)
答案 0 :(得分:1)
如果您只想删除整个重复文件,则执行任务非常简单。
您必须浏览所有文件夹并散列每个文件的内容。产生的散列具有一些比特(例如32到256比特)。 如果两个文件哈希相等,则相应文件相同的概率极高(取决于哈希函数的冲突阻力,读取位数)。
当然,现在实现取决于你(我不是C#或VB程序员)但我建议你使用类似下面的伪代码(接下来我解释每一步并给你链接演示如何做到这一点在C#):
do{
file_byte_array = get_file_contents_into_byte_array(file) 1
hash = get_hash from_byte_array(file_byte_array); 2
if(hashtable_has_elem(hashtable,hash)) 3
remove_file(file); 4
else 5
hashtable_insert_elem(hashtable,hash,file); 6
}while_there_are_files_to evaluate 7
此逻辑应在所有 .pst 文件上执行。在第1行(我假设您已打开文件),写下file into a byte array. 的所有内容
获得文件的字节数组后,必须使用散列函数对其进行散列(第2行)。您有很多哈希函数实现可供选择。在某些实现中,您必须将文件分成块并散列每个块内容(例如here,here和here)。 如果您的文件非常庞大并且不适合您的记忆,那么打破部分文件可能是唯一的选择。另一方面,您有许多接受整个流的功能(例如{{ 3}}, here一个与你的问题非常相似的例子,here,here,但我建议你超级快here) 。如果您有效率要求,请远离加密哈希函数,因为它们更重,并且您不需要加密属性来执行任务。
最后,在计算哈希之后,您只需要通过某种方式保存哈希值并进行比较,以便找到相同的哈希值(读取文件)并删除它们(第3-6行)。我的目的是使用MurmurHash3或hash table,其中标识符(用于执行查找的对象)是文件哈希,对象文件是条目值。
<强> 注意: 强>
请记住!!!: 哈希值的位数越多,冲突概率就越小。如果您想了解有关哈希函数中碰撞概率的更多信息阅读此dictionary。您必须注意此主题,因为您的目标是删除文件。 如果您遇到了碰撞,那么您将删除一个不相同的文件,您将永远将其丢失。有许多策略可以识别碰撞,您可以将它们组合并添加到您的算法中(例如,比较文件大小,比较随机位置的文件内容值,使用多个哈希函数)。我的建议是使用所有这些策略。如果使用两个散列函数,那么对于两个文件被认为是相同的,它们必须具有相等的每个散列函数的散列值:
file1, file2;
file1_hash1 = hash_function1(file1);
file2_hash1 = hash_function1(file2);
file1_hash2 = hash_function2(file1);
file2_hash2 = hash_function2(file2);
if(file1_hash1 == file2_hash1 &&
file2_hash2 == file2_hash2)
// file1 is_duplicate_of file2;
else
// file1 is_NOT_duplicate_of file2;
答案 1 :(得分:1)
通过首先递归查找所有PST文件,然后匹配文件长度,然后按固定的字节前缀进行过滤,最后执行完整哈希或字节比较以获得实际匹配,我将通过查找重复项的过程工作。
递归地构建列表并找到可能的匹配可以这么简单:
Func<DirectoryInfo, IEnumerable<FileInfo>> recurse = null;
recurse = di => di.GetFiles("*.pst")
.Concat(di.GetDirectories()
.SelectMany(cdi => recurse(cdi)));
var potentialMatches =
recurse(new DirectoryInfo(@"m:\mail"))
.ToLookup(fi => fi.Length)
.Where(x => x.Skip(1).Any());
potentialMatches
查询按文件大小为您提供了一系列完整的匹配。
然后我将使用以下函数(我将实现留给您)来进一步过滤此列表。
Func<FileInfo, FileInfo, int, bool> prefixBytesMatch = /* your implementation */
Func<FileInfo, FileInfo, bool> hashMatch = /* your implementation */
通过按文件长度限制匹配,然后通过字节前缀限制匹配,您将显着减少非常大的文件所需的哈希计算。
我希望这会有所帮助。