YAOTU INSIGHTS

dupeGuru 开发者指南:从 Big Picture 到源码级架构解析

dupeGuru 开发者指南:从 Big Picture 到源码级架构解析
桌面应用【免费下载链接】dupeguruFind duplicate files项目地址https://gitcode.com/gh_mirrors/du/dupeguru点击查看免费下载导读dupeGuru 是一个跨平台的重复文件查找工具其代码库横跨core核心逻辑、hscommon公共库与qt/cocoa等平台 UI 层。本文以仓库中的 开发者指南 为主体梳理 dupeGuru 的大图景Big Picturegit 分支与发布策略、以DupeGuru类为中心的非正统 MVC 结构、内置的线程化 Job 机制以及core.engine→core.results的重复匹配核心链路并结合源码给出调用关系与实现细节。读完本文你将具备快速定位 dupeGuru 任意功能入口、理解扫描与去重全流程的能力为二次开发或代码审计打下基础。一、git 分支与发布模型dupeGuru 的 git 仓库只有一个主分支master。按 开发者指南 的约定master代表最新的稳定开发提交latest stable development commit即不包含进行中功能的最近一次提交master必须始终可构建且 tox 必须能在该分支上无错误运行当某个功能/修复具备单次提交的原子性时可以直接提交到master若需要多个提交完成则应放入独立的 topic 分支直到功能就绪后再合入每个发布版本都打上版本号 tag例如 v2.8.2 对应2.8.2tag。这套约定保证了任何人在任意时刻 clone 仓库都能得到一个可运行、可测试的状态也明确了进行中的大功能必须隔离的协作纪律。二、Model/View/Controller……不存在的架构现实开发者指南开篇就坦率承认dupeGuru 代码库存在不少设计缺陷Model、View、Controller 三种角色由分散在各处的不同类分担。理解这一点是看懂代码的第一步。2.1 中枢类core.app.DupeGuru无论哪一平台Qt、Cocoa 或命令行GUI 代码访问 Python 核心的唯一入口都是core.app.DupeGuru。它是整个应用的中枢典型 API 包括启动扫描DupeGuru.start_scanning()core/app.py添加目录DupeGuru.add_directory()core/app.py移除重复项DupeGuru.remove_duplicates()core/app.py以add_directory为例其实现将添加路径委托给self.directories.add_path()并针对两种失败场景向用户弹出消息def add_directory(self, d): try: self.directories.add_path(Path(d)) self.notify(directories_changed) except directories.AlreadyThereError: self.view.show_message(tr({} already is in the list.).format(d)) except directories.InvalidPathError: self.view.show_message(tr({} does not exist.).format(d))可以看到DupeGuru通过self.view与 GUI 解耦核心层只关心逻辑与状态变更notify(directories_changed)视图层负责弹窗等表现细节。2.2 平台子类与同名异实现DupeGuru的大量功能被实现为平台相关的子类。以从结果中移除所选Remove Selected From Results为例Cocoa 侧RemoveSelected()PyQt 侧remove_duplicates()两边的类名相同都叫DupeGuru、职责相同但方法命名与具体 UI 集成方式不同。在本仓库中可以看到 Qt 侧对应实现位于 qt/app.py而核心逻辑core.app.DupeGuru.remove_duplicates会进一步调用self.results.remove_duplicates()并广播results_changed_but_keep_selection通知core/app.py。这种核心逻辑收敛 平台薄壳的设计正是理解三套 UISE/ME/PE代码的基础先找core.app.DupeGuru再找平台子类覆盖的钩子方法。三、Job内建的多线程任务机制dupeGuru 中有大量耗时操作扫描、加载、复制/移动/删除因此DupeGuru内置了一套通用线程化 Job 机制。3.1 ThreadedJobPerformer 与 progressDupeGuru有一个progress成员它是hscommon.jobprogress.performer.ThreadedJobPerformer的实例负责在后台线程执行任务、并通过回调向 GUI 汇报进度。当DupeGuru需要启动一个 Job 时它调用_start_job()由平台特定子类处理启动细节。核心层的_start_job实现如下core/app.pydef _start_job(self, jobid, func, args()): title JOBID2TITLE[jobid] try: self.progress_window.run(jobid, title, func, argsargs) except job.JobInProgressError: msg tr( A previous action is still hanging in there. You cant start a new one yet. Wait a few seconds, then try again. ) self.view.show_message(msg)几个值得注意的点Job 有明确类型JobType.SCAN、JobType.LOAD、JobType.COPY、JobType.MOVE、JobType.DELETE等_job_completed()会根据 jobid 决定后续动作显示结果窗口、刷新结果表、弹出成功/失败消息等见 core/app.py并发保护若上一个 Job 仍在运行会抛出JobInProgressError并提示用户等待避免同一时间叠加多个后台任务错误处理_job_error()对 LOAD 类任务失败给出可读消息其余错误则直接上抛。3.2 扫描流程中的 Job 使用以start_scanning为例core/app.py整个扫描被封装在一个do(j)回调中交给_start_job(JobType.SCAN, do)设置fs.filesdb.ignore_mtime依据rehash_ignore_mtime选项决定是否忽略 mtime 以复用哈希缓存若所选目录无任何可扫描文件直接提示并返回将self.options中 scanner 具备的同名属性下发到 scanner 实例清空self.results.groups并重建结果表在 Job 回调内先j.set_progress(0, ...)汇报正在收集文件再用self.directories.get_files(...)收集文件列表FOLDERS 扫描则收集文件夹可选按ignore_hardlink_matches去除硬链接重复项最后调用scanner.get_dupe_groups(files, self.ignore_list, j)产出分组结果支持profile_scanTrue时启用cProfile把性能剖析结果 dump 到 appdata 下的.profile文件。这正是耗时操作一律走 Job、GUI 全程保持响应的机制落地。四、核心原则engine 与 results 的分工4.1 匹配管线getmatches→get_groups重复匹配的核心对 SE 和 ME 而言PE 照片匹配走独立路径位于core.enginecore/engine.py由两个关键函数构成core.engine.getmatches(objects, ...)接收一组core.fs.File实例返回(firstfile, secondfile, match_percentage)三元组形式的Match列表core/engine.pycore.engine.get_groups(matches)接收 Match 列表返回一组Group实例——Group本质上是互相匹配的文件列表core/engine.py。getmatches 的内部逻辑getmatches是基于词袋的模糊匹配其执行步骤含默认参数参数默认值含义min_match_percentage0匹配的最低词匹配百分比阈值match_similar_wordsFalse是否让相似词经merge_similar_words处理参与匹配weight_wordsFalse长词是否在百分比计算中权重更高no_field_orderFalse按字段field匹配时是否忽略顺序jjob.nulljobJob 进度实例算法大致为对每个对象计算words若尚未缓存getwords(o.name)build_word_dict建立词 → 对象集合的倒排索引reduce_common_words(word_dict, 50)削减出现频率过高的常见词阈值 50若开启match_similar_words调用merge_similar_words合并近似词按词袋倒排做两两比较get_match(ref, other, flags)计算百分比达到阈值的记入结果。值得注意的两个边界设计内存保护LIMIT 5000000匹配数达到上限即提前返回外层用MemoryError捕获内存溢出时带着不完整结果继续跑并logging.warning记录注释明确说明这是扫描期间内存峰值所在Job 进度PROGRESS_MESSAGE tr(%d matches found from %d groups)会在每次迭代中汇报已发现的匹配数与已处理词数。get_groups 的分组策略get_groups先把匹配对按百分比降序排列再用dupe2group字典做并查集式归组两个文件已有组则并入分属不同组则跳过保证同一组内所有文件两两匹配这一不变量MemoryError时释放字典继续。归组后还会收集孤儿匹配组的候选匹配中两个文件都未被组接纳的对它们递归再分组从而不遗漏任何潜在组合。4.2 扫描类型与内容匹配core.scanner.ScanType定义了所有扫描模式core/scanner.pyclass ScanType: FILENAME 0 FIELDS 1 FIELDSNOORDER 2 TAG 3 FOLDERS 4 CONTENTS 5 # PE FUZZYBLOCK 10 EXIFTIMESTAMP 11Scanner._getmatchescore/scanner.py据此分派CONTENTS与FOLDERS扫描走engine.getmatches_by_contents按文件大小分组 → 比较 digest 的逐字节内容匹配对大于bigsize的大文件先比较部分哈希digest_partial、再比较抽样哈希digest_samples见 core/engine.py其余类型走基于词的getmatches并透传match_similar_words、word_weighting等选项。文件名扫描时扩展名不参与词匹配相关行为均有 scanner_test.py 中的测试用例覆盖如test_extension_is_not_counted_in_filename_scan。4.3 Results标记、排序与去重的最终舞台扫描结束后get_groups的结果被放入DupeGuru.results——一个core.results.Results实例core/results.py。所有重复标记dupe marking、排序、移除、power marking 等操作都发生在这个类上。它有如下职责分组与去重remove_duplicates(dupes)把指定 dupe 从各自Group中移除组空了则整组删除并同步更新__total_count/__total_size统计core/results.py批量操作perform_on_marked(func, remove_from_results)对全部已标记 dupe 执行func捕获OSError/UnicodeEncodeError记入self.problems最后统一移除并保留失败项core/results.py标记系统标记的底层通用机制来自 core/markable.pymark/unmark/mark_toggle/mark_all/mark_invert/mark_count等Results通过继承复用并重写_is_markable/_did_mark/_did_unmark钩子来联动统计与视图刷新持久化save_to_xml/load_from_xml以 XML 保存分组、词、ref 与标记状态对应测试见 results_test.py过滤apply_filter(filter_str)支持对结果做字符串过滤大小写不敏感相关测试test_filter_is_case_insensitive在 results_test.py 中。4.4 参考文件ref与without_ref每个Group有一个refreference文件即组内不会被删除的保留文件。GUI 上的标记后删除等操作一律排除 refDupeGuru.without_ref()会过滤掉每个组中的 ref 元素core/app.pymake_selected_reference()则允许用户更换组内 ref。ref 的存在让哪份保留、哪份删除的决策显式化是结果操作语义的核心。五、Fields字段匹配的容错设计开发者指南配套的 engine 文档 专门阐述了Fields字段概念这是音乐文件匹配中极具特色的设计。5.1 问题背景音乐文件名常形如My Artist - a very long title with many many words——共 10 个词。若按 90% 的容差做整名匹配能正确找到标题只少一个 many 的重复项但也会产生误报如My Giraffe - a very long title with many many words与原名词重叠度极高却是完全不同的歌曲把它们判为重复毫无意义。5.2 按字段独立匹配开启字段匹配后每个被-分隔的字段作为独立的字符串分别匹配所有字段匹配完成后保留最低结果作为最终百分比。在 Giraffe 例子中结果会从普通模式下的 90% 骤降到 50%从而被阈值排除。底层实现是 core/engine.py 中的getfields与compare_fieldsdef getfields(s): fields [getwords(field) for field in s.split( - )] return [_f for _f in fields if _f] # 丢弃空字段getfields按 - 切分字段再对每个字段做getwordscore/engine.pycompare_fields要求两边字段数量相等若开启NO_FIELD_ORDER则对每个字段在其副本中贪心寻找最佳配对并移除已配字段否则按顺序配对最后取所有字段得分的下限core/engine.py 及后续行。getwords本身做了大量清洗NFD 归一化以便把带重音的 ASCII 字母并入单词、将-_():;\[]{}.,/?~!#$*等字符替换为空格、转小写、丢弃空元素并刻意保留无法净化的高位 Unicode 字符阈值ord(\u037e)希腊问号。这些细节正是文件名匹配的准确性来源对应的测试用例test_unicode、test_splitter_chars、test_decompose_unicode等位于 engine_test.py。六、API 地图如何继续深入开发者指南的 API 一节 通过 Sphinxtoctree组织了完整文档树core 文档appautomodule自动生成core.app全量 API、fs、engine、directories、results、gui含 deletion_optionshscommon 文档涵盖conflict、desktop、notify、path、util以及jobprogress/*Job 机制与 performer和gui/*表格、树、文本域等公共控件。对应源码目录core/app.py、engine.py、fs.py、directories.py、results.py、scanner.py、markable.py、exclude.py、ignore.py、prioritize.py、export.pyhscommon/jobprogress/job.py、jobprogress/performer.py线程化执行器、gui/下的通用控件三个产品版各自封装core/se标准版文件名/内容扫描、core/me音乐版标签字段匹配、core/pe照片版matchblock模糊块匹配 matchexifEXIF 时间戳匹配GUI 分别位于qt/se、qt/me、qt/pe。七、给开发者的实践建议从core.app.DupeGuru入手任何功能需求先在 core/app.py 找同名公开方法找不到再看平台子类是否覆写。理解通知-刷新模式核心层改状态后用self.notify(...)广播directories_changed、results_changed、marking_changed、dupes_selected等GUI 控件据此刷新别试图在核心层直接操作控件。耗时操作务必走 Job新增功能若耗时仿照start_scanning用_start_job(jobid, do)包装并正确实现_job_completed/_job_error。动手前先跑测试master分支承诺tox全绿核心逻辑改动可先用 core/tests 下的app_test.py、engine_test.py、scanner_test.py、results_test.py验证行为。善用文档树Sphinx 生成的 API 文档automodule覆盖全部公开成员配合源码阅读可快速定位任何签名与默认值。本文基于仓库 help/en/developer/index.rst 及配套的 engine 文档 编写所有源码引用均指向当前仓库实际文件与已验证的行号可对照阅读。赞分享桌面应用【免费下载链接】dupeguruFind duplicate files项目地址https://gitcode.com/gh_mirrors/du/dupeguru点击查看免费下载相关推荐dupeGuru 开发者指南深入理解代码架构与核心机制dupeGuru 开发者指南深入理解代码架构与核心机制 项目概述 dupeGuru 是一款高效的重复文件查找工具其核心功能是通过智能算法快速识别计算机中的重桌面应用ALVR开发者完全指南从源码构建到架构深度解析ALVR开发者完全指南从源码构建到架构深度解析 ALVRAir Light VR是一个开源的虚拟现实串流解决方案能够将PC上的VR游戏通过Wi Fi无线音视频图形学Chili3d 开发者编码指南全解从构建命令到核心架构模式的源码级剖析Chili3d 开发者编码指南全解从构建命令到核心架构模式的源码级剖析 本篇指南基于仓库根目录 AGENTS.md https://link.gitcode.前端图形学3D渲染插件系统上一篇推荐使用昔日之星物理引擎PhysicsJS下一篇探索高性能负载测试工具loadtest创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考