← 返回首页

家庭文件如何校验:用 SHA-256 检查复制前后是否一致

把家庭照片、扫描件或视频复制到移动硬盘后,文件数量和大小看起来相同,内容就一定完整吗?想进一步确认,可以给复制前后的文件各算一次 SHA-256,再比较结果。

这一步适合搬家式的数据迁移、重要文件归档,以及从备份中恢复文件后的检查。它能帮助发现变化,但前提是你保留了可信的原文件或历史校验值。

校验和检查的是什么

SHA-256 会根据输入字节生成一个 256 位摘要,通常写成 64 个十六进制字符。文件名不同,内容相同,摘要仍会相同;照片的 EXIF 信息、文本换行或文档内部数据改变,都可能让摘要改变。NIST 的哈希函数说明介绍了这一类固定长度摘要。

实际家庭文件检查中,相同的 SHA-256 可以作为内容一致的有力证据,但不能把它写成数学意义上的绝对保证:不同输入理论上可能发生碰撞。不同摘要则明确意味着输入字节不同。

下面的示例会创建独立的临时目录和演示文件,不碰你的照片。它们演示三个步骤:记录原始摘要、检查副本、修改副本后再次检查。命令依据官方文档整理;文中的输出描述是预期结果,不代表在三种操作系统上都完成了实机测试。

Windows:使用 PowerShell

打开 PowerShell,粘贴整段代码。使用随机目录避免覆盖已有文件,-ErrorAction Stop 则让读取失败直接报错,不把失败当成校验结果。

$ErrorActionPreference = 'Stop'
$dir = Join-Path $env:TEMP ('sha256-demo-' + [guid]::NewGuid())
New-Item -ItemType Directory -Path $dir | Out-Null
$original = Join-Path $dir 'original.txt'
$copy = Join-Path $dir 'copy.txt'
$record = Join-Path $dir 'original.sha256'

[System.IO.File]::WriteAllBytes($original, [byte[]](97, 98, 99))
$before = (Get-FileHash -LiteralPath $original -Algorithm SHA256).Hash
$before | Set-Content -LiteralPath $record -Encoding ascii
Copy-Item -LiteralPath $original -Destination $copy

$expected = (Get-Content -LiteralPath $record -Raw).Trim()
$after = (Get-FileHash -LiteralPath $copy -Algorithm SHA256).Hash
$expected -eq $after

[System.IO.File]::AppendAllText($copy, 'changed')
$changed = (Get-FileHash -LiteralPath $copy -Algorithm SHA256).Hash
$expected -eq $changed
Write-Output "演示目录:$dir"

两次比较预期依次返回 True、False。这里显式指定 SHA256,方便日后看懂记录;-LiteralPath 按原样解释路径,对包含方括号的文件名也更稳妥。参数定义见 Microsoft Get-FileHash 文档。

实际检查时,将 $original 和 $copy 换成两个文件的完整路径,分别运行 Get-FileHash 再比较 .Hash 即可。不要把上面的写入和追加演示命令用于真实文件。

macOS:使用 shasum

打开“终端”,运行:

dir=$(mktemp -d) && (
  cd "$dir" || exit 1
  printf 'abc' > original.txt || exit 1
  before=$(shasum -a 256 original.txt) || exit 1
  cp original.txt copy.txt || exit 1
  after=$(shasum -a 256 copy.txt) || exit 1
  [ "${before%% *}" = "${after%% *}" ] || exit 1
  printf '原文件与副本摘要一致\n'
  shasum -a 256 copy.txt > copy.sha256 || exit 1
  shasum -a 256 -c copy.sha256 || exit 1
  printf 'changed' >> copy.txt || exit 1
  shasum -a 256 -c copy.sha256
)
printf '演示目录:%s\n' "$dir"

代码先比较原文件与副本的摘要,只有一致才继续创建副本清单。第一次校验预期显示 copy.txt: OK;追加内容后,第二次预期显示 FAILED,并返回失败状态。

-a 256 选择 SHA-256,-c 从清单读取摘要和文件名再校验。Apple 的代码签名技术说明使用了这一计算命令,完整选项见 Perl 官方 shasum 文档。

Linux:使用 sha256sum

以下适用于提供 GNU Coreutils sha256sum 的系统:

dir=$(mktemp -d) && (
  cd "$dir" || exit 1
  printf 'abc' > original.txt || exit 1
  before=$(sha256sum original.txt) || exit 1
  cp original.txt copy.txt || exit 1
  after=$(sha256sum copy.txt) || exit 1
  [ "${before%% *}" = "${after%% *}" ] || exit 1
  printf '原文件与副本摘要一致\n'
  sha256sum copy.txt > copy.sha256 || exit 1
  sha256sum -c copy.sha256 || exit 1
  printf 'changed' >> copy.txt || exit 1
  sha256sum -c copy.sha256
)
printf '演示目录:%s\n' "$dir"

流程与 macOS 相同:生成清单,校验成功,修改文件,再看到不匹配。工具说明见 GNU SHA-2 utilities 手册。报错措辞可能随系统语言不同。

给真实文件留下可靠基线

正式迁移时,沿用演示中的顺序:在复制前为源文件生成摘要,复制完成后再计算目标文件摘要并比较。不能只给目标文件建清单就认定复制正确。文件较大时,计算需要读取完整内容,等待时间取决于文件大小及存储设备;在结果出来前,不要删除原件。

先等同步、导出和编辑结束,再计算摘要。保存算法名称、文件路径、日期及摘要;将基线另存一份,避免与文件一起丢失或被覆盖。使用相对路径清单时,要在正确目录执行校验。移动或重命名文件可能导致“找不到文件”,这不等于内容损坏。

校验通过也只覆盖所检查的文件,不会自动证明整个文件夹没有漏复制。批量归档还要核对文件清单,尤其留意隐藏文件和不同子目录中的同名文件。

不匹配时先保留两份文件,检查是否选错版本、文件尚未传完,或软件自动修改了元数据。不要为了让校验通过,直接用新摘要覆盖旧记录。

校验不能代替备份,也不证明来源

摘要能帮助发现文件变了,却不能恢复照片。原文件和副本一起损坏时,一个摘要无法把它们修好。保留独立备份,并实际尝试恢复,仍然必要。

同样,攻击者若能同时替换文件和校验清单,就能提供一组彼此匹配的新内容。下载软件时,应从可信发布渠道取得预期摘要;需要验证发布者时,还要检查官方签名及其信任关系。NIST 的密码机制指南明确区分了单独哈希与来源认证。

对家庭文件来说,最实用的习惯很简单:保存原件,记录摘要,复制后核对,并保留能够恢复的备份。

写于此,留待再读。