在日常开发中,我们经常需要验证下载文件的完整性——比如官方发布的软件包通常会附带 SHA256 校验值。手动敲 sha256sum 命令虽然能用,但在 Windows 上并不原生支持,而且无法批量处理目录。
今天我们用 OpenCode 在 4 分钟内做一个跨平台的命令行文件哈希校验工具,支持 MD5、SHA1、SHA256、SHA512 四种算法,单文件和目录批量处理,以及文件完整性校验模式。所有功能都可以直接用在 CI 流水线中。
技术栈:Python 3.8+,纯标准库,零依赖。
在终端中输入 opencode 启动,连接后即可用自然语言交互。
我对 OpenCode 说:
> 帮我写一个 Python 命令行脚本,接收一个文件路径,计算它的 SHA256 哈希值并输出。使用 argparse 处理参数,支持通过 -a 参数指定算法(可选 md5/sha1/sha256/sha512)。
OpenCode 立即在工作目录下生成了 hashcheck.py,核心思路是使用 hashlib.new() 动态选择算法,分块读取文件避免大文件撑爆内存:
def hash_file(filepath: Path, algorithm: str) -> str:
h = hashlib.new(algorithm)
with open(filepath, "rb") as f:
while True:
data = f.read(65536)
if not data:
break
h.update(data)
return h.hexdigest()
运行测试:
$ python hashcheck.py README.md -a sha256 e3b0c44298fc1c149afbf4c8996fb924... README.md
关键要点:OpenCode 选择了 hashlib.new() 而非写死 hashlib.sha256(),这让后续扩展算法时无需改动核心逻辑——一次写对,受益全程。
我对 OpenCode 说:
> 再加个功能:如果传入的是目录路径,递归扫描所有文件并分别计算哈希。文件按路径排序,用相对路径显示。再加个 -g 参数支持文件匹配模式。
OpenCode 新增了 scan_files() 函数,用 Path.rglob() 递归遍历,自动兼容了 Windows 和 Unix 的路径分隔符。输出格式与单文件模式保持一致,加上了耗时统计:
def scan_files(directory: Path, pattern: str = "*") -> list[Path]:
files = []
for p in sorted(directory.rglob(pattern)):
if p.is_file():
files.append(p)
return files
我对 OpenCode 说:
> 再加一个 -c 参数:用户传入期望的哈希值,脚本计算实际值后比对,输出通过或失败。校验通过返回退出码 0,失败返回 1,这样能用在 CI 脚本里。
OpenCode 理解了退出码的重要性,添加了校验分支,失败时还会打印期望值和实际值方便排查:
$ python hashcheck.py app.tar.gz -a sha256 -c d4f3e2... ✗ 校验失败 期望: d4f3e2... 实际: a1b2c3d4... $ echo $? 1
我对 OpenCode 说:
> 美化一下输出,校验通过用绿色,失败用红色。目录模式下最后汇总显示总耗时和文件总数。
OpenCode 用了 ANSI 转义码做颜色输出,time.perf_counter() 做精确计时。最终效果:
d4f3e2a1... src/main.py [0.002s] 7b8c9d0e... src/utils.py [0.001s] a1b2c3d4... README.md [0.001s] 共 3 个文件,总耗时 0.01s
就这样,四次对话、四分钟,一个功能齐全的文件哈希校验工具就完成了。
#!/usr/bin/env python3
"""文件哈希校验工具 — 支持 MD5/SHA1/SHA256/SHA512"""
import hashlib
import argparse
import sys
import time
from pathlib import Path
ALGORITHMS = ["md5", "sha1", "sha256", "sha512"]
BUF_SIZE = 65536
def hash_file(filepath: Path, algorithm: str) -> tuple[str, float]:
h = hashlib.new(algorithm)
start = time.perf_counter()
with open(filepath, "rb") as f:
while True:
data = f.read(BUF_SIZE)
if not data:
break
h.update(data)
elapsed = time.perf_counter() - start
return h.hexdigest(), elapsed
def scan_files(directory: Path, pattern: str = "*") -> list[Path]:
files = []
for p in sorted(directory.rglob(pattern)):
if p.is_file():
files.append(p)
return files
def main():
parser = argparse.ArgumentParser(
description="文件哈希校验工具 — 计算 MD5/SHA1/SHA256/SHA512"
)
parser.add_argument("path", help="文件或目录路径")
parser.add_argument(
"-a", "--algorithm", default="sha256",
choices=ALGORITHMS, help="哈希算法(默认 sha256)"
)
parser.add_argument(
"-c", "--check", metavar="HASH",
help="校验模式:与给定哈希值比对(仅限单个文件)"
)
parser.add_argument(
"-g", "--glob", default="*",
help="文件匹配模式,目录模式下生效(默认 *)"
)
args = parser.parse_args()
target = Path(args.path)
if not target.exists():
print(f"\033[31m错误:\033[0m 路径不存在 — {args.path}", file=sys.stderr)
sys.exit(1)
if args.check:
if not target.is_file():
print("\033[31m错误:\033[0m 校验模式仅支持单个文件", file=sys.stderr)
sys.exit(1)
actual, elapsed = hash_file(target, args.algorithm)
if actual == args.check.lower():
print(f"\033[32m✓ 校验通过\033[0m ({args.algorithm}, 耗时 {elapsed:.3f}s)")
else:
print(f"\033[31m✗ 校验失败\033[0m")
print(f" 期望: {args.check.lower()}")
print(f" 实际: {actual}")
sys.exit(1)
return
if target.is_file():
h, elapsed = hash_file(target, args.algorithm)
print(f"{h} {target.name} ({elapsed:.3f}s)")
elif target.is_dir():
files = scan_files(target, args.glob)
if not files:
print(f"目录中无匹配文件(模式: {args.glob})")
return
total_start = time.perf_counter()
for fp in files:
h, elapsed = hash_file(fp, args.algorithm)
rel = fp.relative_to(target)
print(f"{h} {rel} [{elapsed:.3f}s]")
total = time.perf_counter() - total_start
print(f"\n共 {len(files)} 个文件,总耗时 {total:.2f}s")
else:
print("\033[31m错误:\033[0m 不支持的路径类型", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
整个开发过程只用了 4 分钟、4 次对话迭代,从单文件哈希到目录批处理再到校验模式,一气呵成。实际手写这些功能即使熟练也要 15-20 分钟,OpenCode 把效率提升了 4-5 倍。
这次实践最让我印象深刻的是,OpenCode 对 Python 标准库的理解非常精准——Path.rglob() 递归遍历、hashlib.new() 动态算法选择、time.perf_counter() 高精度计时,每个 API 的选型都很到位,没有引入不必要的第三方依赖。只要你把需求描述清楚,它生成的代码就是可以直接投产的。
如果你也想体验用自然语言编程的效率,不妨从这个小工具开始试试 OpenCode。