让AI复核重复文件:先在本地算SHA256,只分组不删除

“海报最终版”和“海报最终版-副本”看起来像重复,文件名却不能证明内容一样。让 AI 直接看名字列删除名单,风险很大。更稳妥的做法是先在本地算 SHA256,给每份文件一个编号,再让 AI 审核分组理由和缺失证据。这个练习到复核清单为止,不移动、不改名、更不删除任何文件。

适合谁,需要准备什么

适合想核对导出稿、附件副本或归档拷贝的人。本文命令面向 Windows 的 PowerShell,使用普通权限即可;先用自己创建的练习目录,不要扫描整个磁盘、系统目录或正在同步的项目。准备能执行 Get-FileHash 的 PowerShell,以及一款文字 AI。系统已有相应命令时无需额外购买查重软件;AI 额度与费用依所选服务,不需要专门开通 API。

打开 PowerShell,输入 Get-Command Get-FileHash 确认命令可用。若提示不存在,停止在当前终端试跑,查阅微软官方安装文档,不要下载陌生“去重神器”或绕过执行策略。这里的 PowerShell 示例已按官方参数核对,但本文没有把它描述为本机实跑结果;下面单列的合成样本摘要则确实由 Python 标准库计算。

先定边界:相同字节与看起来相似是两件事

Get-FileHash 官方文档说明,该命令根据文件内容计算摘要,默认算法为 SHA256。文件改名不改变其内容摘要;同名文件也可能有不同摘要。对普通归档复核,同样字节数与相同完整 SHA256 可作为“字节一致候选”的强证据,但不要把哈希当成数学上绝无碰撞的证明,也不要拿前八位代替完整值。

一张照片仅改了元数据、文档换了编码、文本从 LF 换成 CRLF,画面或文字可能几乎不变,字节却不同。这类“内容相似”不属于本练习的同字节分组范围。反过来,两份相同字节的文件也可能必须分别保留:它们可能是两个项目的交付凭证或刻意留存的备份。内容判定不自动产生处置权限。

第一步:让 AI 写出复核规则,而非清理脚本

先发这段提示词,要求 AI 明确证据范围。原文件、真实文件名和目录路径不需要交给它。

我只做文件重复复核,不做清理。请为编号清单制定审查规则。
我会在本地计算 SHA256,只提供 ID、Bytes、SHA256、Status。
请按以下规则输出模板:
1. 仅 Status=OK、Bytes>0 的行可进入普通重复候选分组。
2. 只有字节数相等且完整 64 个十六进制字符的 SHA256 相等,才合为一组;不得按名称、长度或哈希前缀猜测。
3. 空文件另列,ERROR/CHANGED 另列待重算;不能把两个空白摘要分成重复组。
4. 不同哈希只说明未通过字节一致比较,不能据此判断语义是否相似。
5. 输出分组依据、异常记录和人工复核问题;不输出删除、移动、改名或自动修复命令。
如果我的清单格式错误、ID 重复或摘要不完整,先指出问题,不补造值。

第二步:只读列出一个练习文件夹

先关闭正在编辑这些练习文件的应用。把少量非敏感文件副本放到 C:\AI-Practice\hash-demo,至少包含一对直接复制出来的文件,以及一份改过字的文件。核实路径后,在 PowerShell 中粘贴下面代码;路径不存在会报错,不会自动扩大扫描范围。

$root = 'C:\AI-Practice\hash-demo'  # 改成自己的练习文件夹
$files = @(Get-ChildItem -LiteralPath $root -File -ErrorAction Stop |
  Where-Object { -not ($_.Attributes -band [IO.FileAttributes]::ReparsePoint) } |
  Sort-Object Name)
$i = 0
$manifest = @(
  foreach ($f in $files) {
    $i++
    $hash = ''
    $status = 'OK'
    $bytes = $null
    try {
      $f.Refresh()
      $bytes = $f.Length
      $stamp = $f.LastWriteTimeUtc
      $hash = (Get-FileHash -LiteralPath $f.FullName -Algorithm SHA256 -ErrorAction Stop).Hash
      $f.Refresh()
      if ($f.Length -ne $bytes -or $f.LastWriteTimeUtc -ne $stamp) {
        $status = 'CHANGED'
        $hash = ''
      }
    } catch {
      $status = 'ERROR'
      $hash = ''
    }
    [pscustomobject]@{
      ID = ('F{0:D3}' -f $i)
      File = $f.Name
      Bytes = $bytes
      SHA256 = $hash
      Status = $status
    }
  }
)
# 本地查看:文件名留在自己电脑,不发给 AI。
$manifest | Format-Table ID, File, Bytes, Status -AutoSize
# 给 AI 的最小清单:输出到屏幕,不写文件、不删除文件。
$manifest | Select-Object ID, Bytes, SHA256, Status | ConvertTo-Csv -NoTypeInformation

这段代码只读文件,把清单留在当前会话变量和屏幕中。它不使用 -Recurse,因此不扫描子目录;默认也不纳入隐藏文件,列出的符号链接等重解析点会被过滤(硬链接不属于此类)。Get-ChildItem 文档可查这些范围参数。不要把“这一层没查到”写成“整台电脑没有重复”。-LiteralPath 会把方括号等字符当路径本身处理,避免意外按通配符匹配。

如果读取失败,Status 是 ERROR;读取前后长度或修改时间变化则为 CHANGED,两种情况下摘要都留空。这只是基本的变化检查,并非能证明活动文件从未变化的锁定机制,所以练习应使用关闭编辑器后的静态副本。ConvertTo-Csv 仅产生 CSV 字符串,不同于写文件的 Export-Csv。需要保存记录时,可把屏幕输出复制到新建文本文件,避免覆盖原件。编号只对应本次扫描,重新扫描后可能变化;报告必须和同一批原始清单一起保存,不能跨批次按 ID 对照。

第三步:用一份已知样本检查 AI 有没有乱分组

下面是原创合成样本的实际 SHA256 结果,不是随手编的占位哈希。A 与 B 的字节均为 ASCII 文本 Cut 07: blue cup. 加一个 LF 换行;C 的正文相同,结尾改为 CRLF;D 是 Cut 07: gray cup. 加 LF;E 为零字节文件。样本只用来验证规则,不代表你的文件。若手动重建时编辑器加入 BOM 或换行不同,摘要也会不同。

ID,Bytes,SHA256,Status
A,18,9C2068E27075F420820243DA1392DBC72E88508361F49EA26B25239254F65DA9,OK
B,18,9C2068E27075F420820243DA1392DBC72E88508361F49EA26B25239254F65DA9,OK
C,19,72DB2680EF301A57B2CFC60094F34190400E653A89A44A88EF34E26B393AA64A,OK
D,18,4712D6571B8014451E88F5F406E50B0945DA7A24BD29337581487436265DB11D,OK
E,0,E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855,OK

把这五行与前面的规则一起交给 AI,要求输出一份审核结果。你应当看到:A、B 是唯一普通候选组;C 和 D 没有进入该组;E 单列为空文件。C 的正文虽然相同,换行字节不同;D 与 A 同为 18 字节,但正文不同。如果 AI 把 A、B、D 因相同大小归成一组,或把 C 当成“可以安全删除的近似副本”,就要求它回到完整哈希逐行核对。

可再加入一条 F,18,,ERROR 作为异常练习。正确结果必须把 F 放到待重算,而不是把空摘要当成一种有效内容。这个反例能查出模型只按表格表面做聚类的问题。

第四步:用本地分组核对 AI,再逐组写结论

不要只信 AI 对长字符串的阅读能力。在同一 PowerShell 会话运行以下只读分组,比较成员编号是否一致:Group-Object 可按多个属性分组,这里同时使用字节数和完整摘要。

$groups = $manifest |
  Where-Object { $_.Status -eq 'OK' -and $_.Bytes -gt 0 } |
  Group-Object Bytes, SHA256 |
  Where-Object { $_.Count -gt 1 }
$groups | ForEach-Object {
  $_.Group | Select-Object ID, File, Bytes, SHA256
} | ConvertTo-Csv -NoTypeInformation

若没有输出,只表示这次成功读取且非空的文件中未出现候选组,不表示失败项、子文件夹或内容相似文件已经检查过。分组结果先在本地看;发给 AI 时仍可只给编号,省去有隐私的文件名。普通哈希不是匿名化保证,公开文件的摘要也可能被识别;敏感资料的清单留在本地,或按组织允许的工具处理。

最后让 AI 按“组号、成员编号、证据、人工待确认事项”整理报告。例如:“G1:A/B,18 字节且 SHA256 相同;需人工确认是否分别承担备份或交付留存用途。”再由你在本地对照 ID 与文件名,打开候选文件、核对归档需求。不要把“最近修改”“名字带副本”或“路径较短”当成自动保留规则。

常见失败与完成标准

  • 看起来相同,哈希不同:检查编码、换行、元数据或重新导出等差异。若要比较画面或正文,应另开内容比对流程,不能把本次严格规则放宽成自动清理。
  • 读取拒绝或文件在云端:先核实权限与文件是否已按服务正常方式下载。不要提升到管理员或改权限绕过;未读到的条目保持待查。
  • 文件很多、执行很慢:缩小到一个确切目录先试。AI 不应建议扫描整个用户目录;大文件计算摘要本来就要读取内容。
  • 清单交给 AI 后被改了:重新提供原始编号清单,要求只输出独立报告。保留本地原清单,不接受模型改写过的哈希作为证据。

完成时你应得到三类记录:有证据的同字节候选组、未读成或发生变化的待查项、单列的空文件;每组都有人工保留需求待核对。整个目录里的源文件保持原样。到这里就可以结束本次练习,不需要为了“有结果”继续删除或自动整理。

资料核验:2026 年 10 月 29 日。PowerShell 本身是跨平台命令行与脚本环境,本文示例路径按 Windows 编写;非 Windows 环境应替换路径并先做小样本检查。

© 版权声明

相关文章