zoukankan      html  css  js  c++  java
  • 分布式文件快速搜索V7.0(多计算机并行)

    系列文章

    1.分布式文件快速搜索V7.0(多计算机并行/多种算法)

    2.分布式文件快速搜索的设计与实现(开源/分布式计算/并行)

    3.分布式文件快速搜索-技术细节分析(开源/并行)

     

    前言

    这个话题很古老了,用C#实现的也很多,很明显我是在造轮子了。不过我今晚闲得头疼,在codeplex碰见看见一个项目,就是找重复文件的,项目代码我没看,我只是想找事情做。对开发人员来说,舒展一下手指的最佳办法是敲代码了。我最喜欢通过写代码来学东西了,看着枯燥的书本就没劲。

    需求

    找重复文件,首先是要获取文件的特征,很久以前用CRC,虽然最近MD5已经给中国某大学研究员验证不可靠,不过我还是喜欢MD5:)。你可以选择SHA1,换个类名就可以了。

    实现

    实现的办法很简单,就是把所有文件的特征都算出来,然后比较。

    问题是,如果盲目地对每个文件都先获取哈希特征,再进行比较,那会很浪费时间,譬如你的磁盘没有重复文件,或者有些很巨大的不重复文件,那你就要把绝大部分时间浪费在无谓的哈希获取上了。

    所以,我们先使用文件大小进行碰撞,再对相同大小的进行碰撞,可以极大地提高效率。为什么选择文件大小呢?因为如果文件大小不一样,那就不可能内容重复了吧?为什么不同时选择文件的修改时间?文件修改时间不一样,文件内容也是可以一样的,对不?既然我们的目的只是找内容相同的文件(不是文件名相同),那我们就可以无视文件名和文件修改时间了。允许选择不同的特征组合,譬如先是单纯的文件大小,或者文件大小+文件名+创建时间。

    实现过程是用Dictionary来根据特征分组,碰撞(相同文件内容)就放到该特征下的重复文件列表,最后找出所有重复的文件。

    程序很简单,主要是原始文件和重复文件的选择。函数可以指定重复目录,如果匹配到是在重复目录下的,就认为是可删除的(相对保留原始文件而言,本程序没有删除代码。。。)重复的文件,如果没有指定重复目录,则自动选择第一个文件为原始文件。

    并行的实现

    一直想用多线程来实现提速,今晚闲得头疼,就简陋地实现。大概实现步骤:因为不是.NET3.5/4,所以没有PPL,只能模拟并行了:C# Parallelism: Executing Methods in Parallel in .NET 3.5 。原理是封装了ThreadPool,结合ManualResetEvent和WaitHandle.WaitAll等待所有线程完成。在.NET 2.0中,Dictionary不是线程安全的,又不想花时间自己写封装,就只有在网上找了个封装好的线程安全的Dictionary。多线程的思想是:分配任务,分而治之。业务逻辑是自行切割要检索的文件夹到不同的线程,得到结果后,最终实现并行计算。

    网上发现的最quick & dirty的代码

    http://www.hosca.com/blog/post/2010/04/13/using-LINQ-to-detect-and-remove-duplicate-files.aspx

    这个代码极大地让感到我今晚写的代码很冗余。。。它用了几个Linq的语句:Select所有文件,GroupBy哈希值,然后ForEach删除。。。Linq是很精妙。。。不过这个办法跟我的老慢速算法是大同小异的,所以速度也是可以无视的。

    我实现的代码(让你容易找点......)

    老规矩,vs2005+c#2.0,quick & dirty,没linq,没var,没有自动属性。不要跟代码规范较真,也不要纠缠为什么代码都放一个文件,纯粹是为了方便粘贴到博客而已,在产品开发中,6000多个手工写的类我都是很有组织地归类的:)

    代码中有7个算法:

    WorkV1:最原始的,对每个文件都进行哈希值比对;

    WorkV2:较新的算法,先用文件大小(或加上文件名、创建日期、修改日期等)进行过滤,匹配的文件组合才进行哈希值比对;

    WorkV3:新的多线程算法,把多线程应用到文件检索和文件哈希值获取;

    WorkV4:测试发现如果把多线程应用到文件读取,则性能急剧下降,但仅获取文件信息,则有很大提升,虽然瓶颈在文件读取,但起码在检索信息上,比起V2有了提升;

    WorkV5:新的算法,文件检索使用多线程,文件哈希值获取则动态判断文件所在地物理磁盘,如果不是同一个物理磁盘,则是使用多线程,否则采用跟V2一样的算法;因为判断物理磁盘引入了System.Management.dll,使用了DriveIdentification条件编译;

    WorkV6:新的算法,支持对互联网上的计算机进行搜索,哈希值的快速存取,文件内容搜索,全文索引;

    WorkV7:最新的算法,添加了对协议提供者模式的支持,可以自由添加各种访问协议;

    在这里比较性能其实意义不大,以为不同机器比较不同的文件,差异太大了,譬如你的机器有2个文件,一个巨大,一个渺小,用新的快速算法,微秒间完成,用老的慢算法,则你可能要去睡一觉。 

    程序有3个条件编译:DRIVEID启用物理磁盘识别(需要引用System.Management.dll),VERBOSE启用详细的调试信息,LoG启用保存日志

    使用

    看代码,判断支持多个文件夹。先Find出重复文件组合(指纹/相同文件列表),再用FindAll找出可以删除的所有重复文件。


    如果要实现分布式搜索,必须在被搜索的计算机运行WorkV7Manager的实例,具体参看代码。

    本地搜索

    搜索本地完全一样的文件
    string duplicateFolder = @"d:\backup";
    Dictionary
    <string, MatchFileItem> result;
    BaseWork worker 
    = new WorkV6();
    result 
    = worker.Find(new FileURI[] { new FileURI(@"c:\download\"),  new FileURI(duplicateFolder)}
               , 
    new string[] { }, "", SearchTypes.Size | SearchTypes.Name, MatchTypes.ContentSame);
    List
    <string> duplicatedFiles = worker.FindAll(result, duplicateFolder);


    分布式搜索

    初始化

    //first initialize some settings
    WorkUtils.Initialiaze(new KeyValuePair<stringstring>(), CompressionMethods.GZip, new System.Net.WebProxy());

    服务器端

    服务器端
    BaseManager manager = new WorkV6HTTPManager();//you can use WorkV6TCPManager
    Dictionary<string, UserAccess> users = new Dictionary<string, UserAccess>();
    users.Add(
    "user"new UserAccess("user""pass", UserRights.Discover | UserRights.Search));
    string[] allowedPaths = new string[] { @"e:\temp\New Folder" };
    manager.Start(users, allowedPaths, 
    8880);

    客户端

    客户端
    FileURI remoteFolder = new FileURI(@"202.2.3.4:8880/e:\temp\New Folder""user""pass"0, ObjectTypes.RemoteURI);
    Dictionary
    <string, MatchFileItem> result;
    result 
    = Worker.Find(new FileURI[] { new FileURI(@"c:\download\"),  remoteFolder }
                , 
    new string[] { }, "YOUR KEYWORD HERE", SearchTypes.Size, MatchTypes.ContentExtract);
    List
    <string> matchFiles = Worker.FindAll(result, string.Empty);

    已知问题

    本程序并没有考虑因为文件量巨大而会造成内存不足等问题,这个就留到以后我闲得更头痛的时候再考虑吧。

    如果你要同时测试多种算法,那是不可能的,因为所有算法的瓶颈是对文件的哈希值获取,而这个方法允许Windows对已经访问的文件进行缓存和预取(pre-fetch),这样当你测试完第一个算法,再用第二个算法的时候,就会发现秒级完成。所以你每测试出一个结果,就应该重启电脑。。。

    未知问题

    如果你发现有什么bug,麻烦告诉我,我喜欢学习:)

    改进

    1.2010-7-16 v1;

    2.2010-7-14 v2 添加了对选择文件名/修改时间/创建时间为重复标准的支持;重构代码,引入了基类,方便测试;

    3.2010-7-14 v2.1 再次重构,并添加了对指定文件类型的支持,允许正则表达式;

    4.2010-7-15 v3 增加了对多线程的支持,速度提升;

    5.2010-7-16 v3.1 修正了从v2开始出现的重复测试问题;

    6.2010-7-16 v4 仅应用多线程于文件查找;

    7.2010-7-16 v5 动态支持多磁盘多线程提速; 

    8.2010-7-16 v5.1 增加了对使用文件属性过滤的支持,并重构了部分代码,并修正了动态多磁盘的判断;

    9.2010-7-19 v5.2 允许单纯地查找匹配大小/文件名而不计算哈希值,增加了对文件名过滤的支持,并重构了部分代码,加入了对动态多磁盘的容错;

    10.2010-7-20 v6 实现了网格搜索

    10.2010-7-20 v6.1 添加了对文件发现的支持,如果远程计算机没有发布可访问的目录,则不进行搜索

    10.2010-7-20 v6.2 添加了对删除重复文件的支持,并改造了用户访问机制 

    11.2010-7-21 v6.3 添加了对快速存取哈希值的支持;

    12.2010-7-21 v6.4 修正了快速存取哈希值的异常问题;

    13.2010-7-23 v6.6 添加了对HTTP协议、内容匹配、全文索引的支持;

    14.2010-7-26 v6.7 添加了对HTTP、TCP压缩传输的支持;

    15.2010-7-28 v6.8 添加了NTFS USN Journal技术,检索文件信息速度提升10倍,源代码:http://filio.codeplex.com/SourceControl/changeset/changes/74232

    16.2010-7-31 v6.9 添加了对基于角色的访问控制(RBAC)的权限管理;

    17.2010-8-11 v7.0 添加了对协议提供者模式的支持;

    TODO

    1.目前来看,改进速度的办法是多线程了,多个线程获取目录文件,然后多个线程对文件列表进行哈希获取。 在V3中添加了对多线程的支持;

    2.添加对分布式(互联网上的机器)的支持;在v6中添加了对网格搜索的支持;

    3.添加对删除文件的支持; 在v6.1中添加了对删除文件的支持;

    4.文件内容哈希值存储,以便以后快速获取(同时记录文件名、大小、修改时间和哈希值,任一不匹配则认为文件改变了)在v6.3中实现了哈希值快速存取

    5.添加对HTTP协议的支持;在v6.6中实现了对HTTP协议的支持

    6.添加对搜索文件内容的支持:完全匹配、全文索引;在v6.6中添加了对文件内容匹配、全文索引的支持;

    7.添加对lucene.net和hubbledotnet的支持; 

    8.添加对缓存的压缩支持;在V6.6添加了对缓存压缩的支持;

    9.添加对网络传输(HTTP/TCP)的压缩支持;在v6.7添加了对网络压缩传输的支持;

    10.添加对文件同步的支持:chunck/index/count,断点续传

    11.添加对基于角色的访问控制(RBAC);在v6.9中添加了对其的支持;

    12.如果检索互联网上的计算机,如果指定搜索目录存在大量的文件,则返回结果可能会因为太大而造成网络超时等问题;

    13.添加对HTTP/TCP的SSL连接的支持;

    14.添加对NTFS的USNJournal支持,可以比普通的检索文件信息(Directory.GetFiles)快10倍。。。 在v6.8中添加了对其的支持

    代码下载

    点击这里下载:Filio.zip

    项目地址

    本项目已经在http://filio.codeplex.com/ 开源

  • 相关阅读:
    hdu 1568 (log取对数 / Fib数通项公式)
    整数对(hdu1271)找规律
    Pupu(hdu3003)数论
    哈密顿绕行世界问题(hdu2181)
    Saving HDU(hdu2111,贪心)
    素数回文(hdu1431)
    Hashmat the brave warrior(UVa10055)简单题
    Moon Game (凸四边形个数,数学题)
    Zipper(poj2192)dfs+剪枝
    不要62(hdu2089)
  • 原文地址:https://www.cnblogs.com/unruledboy/p/DuplicatedFileFinder.html
Copyright © 2011-2022 走看看