重复数据删除.pst文件以查找唯一的电子邮件

时间:2012-10-09 18:20:24

标签: c# .net hash pst deduplication

我有一个(似乎是什么)手头的大任务 我需要浏览多个文件夹的不同存档卷(我们正在谈论数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)

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行)。您有很多哈希函数实现可供选择。在某些实现中,您必须将文件分成块并散列每个块内容(例如hereherehere)。 如果您的文件非常庞大并且不适合您的记忆,那么打破部分文件可能是唯一的选择。另一方面,您有许多接受整个流的功能(例如{{ 3}}, here一个与你的问题非常相似的例子herehere,但我建议你超级快here) 。如果您有效率要求,请远离加密哈希函数,因为它们更重,并且您不需要加密属性来执行任务。

最后,在计算哈希之后,您只需要通过某种方式保存哈希值并进行比较,以便找到相同的哈希值(读取文件)并删除它们(第3-6行)。我的目的是使用MurmurHash3hash 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 */

通过按文件长度限制匹配,然后通过字节前缀限制匹配,您将显着减少非常大的文件所需的哈希计算。

我希望这会有所帮助。