过去这段时间,我一直在做一件挺零碎的事:把散落在各个目录里的文件集中提取成统一格式,该解压的解压,该抓取元数据的抓取元数据,最后整理成一份清单给人用。文件提取这种事看着不复杂,但一旦文件量上千,人工一个个打开看,就是一种精神折磨。后来我换了个思路,让 AI 辅助开发工具来干,前后做了好几个迭代版本,最终沉淀成一个比较稳定的小脚本族。今天把整个过程拆开讲讲,包括我怎么提需求、让 AI 选型、踩过哪些文件处理相关的坑,以及这套工具现在是怎么日常工作的。
先说清楚,这篇文章适合谁。如果你不是专业程序员,但对电脑文件处理比较头疼,想用 AI 辅助写点小工具节省重复劳动,这篇文章能给你一个能落地的参考。如果你本身就是开发,想了解 AI 辅助开发过程中哪些地方容易出问题,我踩过的一些坑应该也能帮到你。我讲的不是那种特别炫的算法,而是真正天天在用的文件提取工具,以及它背后承载的一套工程思路。
1. 做之前先想清楚:文件提取工具的边界在哪里
1.1 我的清理场景究竟是哪种
我手头遇到的典型场景,是你电脑里或工作盘里最常见的那类“内容垃圾场”。比如一个共享目录,里面堆着 PDF、Word、Excel、压缩包、图片,而且文件名乱七八糟,有的叫“最终版”,有的叫“新建文档(1)(1)(1)”,根本看不出内容。如果只是偶尔找一两个文件,问题不大,最怕的是需要一口气知道整个目录里有哪些文件、每个文件大致是什么内容、哪个文件夹占的存储最多、哪些文件明显重复或损坏。
我最初的提取需求,就是把一堆“不知道装着什么的文件”变成一张表格。表格里明确列出:文件的完整路径、扩展名、大小、最后修改时间,以及对于能解析正文的文件,尽量提取一段文本摘要或关键属性。如果是压缩包,提取内部文件清单并解压到指定目录。这个目标一旦清晰,后面让 AI 写代码就少了很多来回扯皮。
所以“文件提取工具”这个名字听起来宽泛,实际落到需求层,必须拆成两个能力:一个是从文档中提取“文本、元数据”,另一个是从容器类文件中提取“里面的文件”。前者用于了解内容,后者用于真正把文件拿出来。AI 能帮上大忙的前提,是你先知道自己到底需要哪一种,而不是让它替你做产品经理。
1.2 为什么要选 AI 辅助而不是直接买现成软件
市面上有很多企业级文件搜索、文档解析工具,尤其像 PDF 批量处理软件,功能动不动就几百块一年。但对我这种场景,问题不是“文件搜索能力不足”,而是“需要围绕自己的目录结构和命名规则定制一套处理流程”。现成软件不会理解你公司内部的归档习惯,也不会主动把结果输出成你 Excel 模板需要的格式。
自己从零写,对很多人来说又有门槛。这就是 AI 辅助开发的甜区:需求足够具体,不追求大而全,只求在特定目录结构上跑得快、结果可控。AI 可以在一两分钟内生成第一版脚本,然后我再根据自己的需求做增量修改。相比以前从网上翻博客拼代码,效率高很多。而且我还不用担心不懂某些库的用法,只要把任务描述清楚,AI 就能告诉我哪些库合适,并直接给出示例代码。
1.3 第一版工具的边界设定
为了避免项目无限扩张,我在动手前给“第一版”划定了几个硬边界:
- 只处理本机目录,不做网络磁盘的实时监控。
- 先支持常见办公文档:PDF、Word(docx)、Excel(xlsx)、纯文本。
- 压缩包先支持 zip,其他格式以后再说。
- 只提取文本摘要和基础属性,不调 OCR,不搞向量化。
- 所有输出统一为 UTF-8 编码的 CSV 文件,方便别人用 Excel 打开。
这几条看起来简单,实际特别重要。因为没有边界的话,AI 很容易往里面加 OCR、图片识别、数据库存储、 Web 界面这些功能,导致代码量膨胀,调试成本直线上升。我能用两三个小时就完成一个能用的版本,核心就是在需求描述里不断告诉 AI:这个阶段只做到什么程度,不许“顺手”加额外功能。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术底座选对了,AI 生成代码才不会跑偏
2.1 选 Python 的原因:不是跟风,而是文件处理库实在太全
第一版工具我用的是 Python 3.10。不是因为 Python 比别的语言更“智能”,而是文件处理生态太完善,AI 对 Python 标准库和第三方库的训练语料也足够多。用一个冷门语言让 AI 生成代码,出错概率明显高很多,尤其是一些编码细节,AI 很容易一本正经地胡诌。Python 里处理文件普遍用到的几个库,已经是社区沉淀十几年、被反复验证过的方案:
bash复制# 或者直接写进 requirements.txt
pypdf==4.2.0
python-docx==1.1.0
openpyxl==3.1.2
这几个库负责不同的文件类型,相互没有冲突。AI 在生成代码时会优先推荐它们,而不是某些冷门库,这本身就是一种“集体经验”的体现。为什么不用 PyPDF2?我的体会是 PyPDF2 维护节奏不稳定,很多老代码解析某些加密 PDF 时会遇到奇怪的报错,而 pypdf 是 PyPDF2 的持续维护分支,API 兼容性也做得比较平滑。反正有 AI 帮忙,切换起来并不费劲。
2.2 让 AI 在编码前先给技术选型方案
很多人在让 AI 写代码时,习惯直接说“帮我写个文件提取脚本”,这样得到的通常是通用模板,用的库可能是 AI 随机猜测的,无法匹配真实环境。我的做法是先不让它写代码,而是让它先给一张技术选型表。
我第一轮提问大概是这样的:
text复制我需要写一个 Python 命令行工具,用来递归读取一个目录下的文件。
目标文件类型包括:PDF、Word(docx)、Excel(xlsx)、ZIP压缩包。
要求:
1. 提取每个文件的路径、大小、修改时间。
2. PDF 额外提取页数和首页前 200 个字符。
3. Word 提取正文第一个自然段。
4. Excel 提取所有 sheet 名称以及每个 sheet 的行列数。
5. ZIP 读取内部文件清单,并支持解压到指定目录。
请先列出推荐的第三方库,并说明每个库的优缺点。不要直接写代码。
这一步效果很好。AI 给出了类似 pypdf、python-docx、openpyxl、zipfile 的列表,还专门提示了一个盲区:docx 本质是 zip 容器,正文在 word/document.xml 里,但如果文件损坏或者扩展名被改过,python-docx 会直接抛异常,所以解析失败时不能中断整个任务。这种提示如果直接让它写代码,很多人可能根本不会意识到。
流程上,我和 AI 的交互一般是先进行“方案设计讨论”,等库选型定了、失败策略定了,再进入写码环节。这样生成的代码第一次能跑通的概率高得多,因为 AI 已经知道上下文的约束条件,不至于每段代码都说“假设你已经有了目标文件”。
2.3 别忘了告诉 AI “不用考虑哪些情况”
我发现 AI 在生成代码时最大的毛病之一,是过度防御。它会假设所有文件都存在、所有权限都正常、所有文件都能被读取,于是不断抛出异常,输出很长很乱的报错逻辑。更麻烦的是,它有机会就会试图引入一些复杂的任务队列或并发框架,增加不必要的心智负担。
所以我通常会在需求后面加一句:
text复制暂时不要考虑 GUI、多线程、数据库、OCR。
单线程即可。
异常处理保持简单:遇到坏文件就跳过并在日志中记录原因,然后继续处理下一个。
AI 很喜欢把简单问题复杂化。你要主动帮它划线,它才会给出和你的水平匹配的代码。这等于提前给 AI 上一道紧箍咒,让它在安全范围内发挥。事实上,我后面真正把工具用于几千文件批量处理时,单线程跑起来也就几十秒,完全没必要为了显高级去上多线程。
3. 实操过程:AI 生成骨架,我负责校验逻辑
3.1 从单目录先跑通,不急着递归
第一版我没让 AI 直接递归处理整个磁盘,只让它处理一个测试目录。这个目录里我故意放了十来个文件,包括:一个没有扩展名的文本文件、一个 PDF 页数 3 页、一个 docx、一个 xlsx、一个 zip 包。等脚本在这个小目录里跑通了,再逐步放开到更深层的目录结构。
AI 生成的初版核心代码长得很像一个“遍历器 + 解析器”的结构,下面这段是后来稳定后的简化版,主流程非常清楚:
python复制from pathlib import Path
import csv
from datetime import datetime
# 支持解析的扩展名
SUPPORTED_TEXT = {".txt", ".md", ".csv"}
SUPPORTED_EXCEL = {".xlsx", ".xlsm"}
SUPPORTED_WORD = {".docx"}
SUPPORTED_PDF = {".pdf"}
def get_file_basic_info(path: Path):
stat = path.stat()
return {
"path": str(path),
"ext": path.suffix.lower(),
"size_bytes": stat.st_size,
"mtime": datetime.fromtimestamp(stat.st_mtime).strftime("%Y-%m-%d %H:%M:%S"),
}
def scan_directory(root_dir: Path, files):
# files 是一个 list[dict]
if not root_dir.exists():
return
for p in root_dir.rglob("*"):
if not p.is_file():
continue
if p.suffix.lower() not in SUPPORTED_TEXT | SUPPORTED_EXCEL | SUPPORTED_WORD | SUPPORTED_PDF:
continue
info = get_file_basic_info(p)
info["summary"] = extract_summary(p)
files.append(info)
这段代码本身不难,但它搭出了整个工具的骨架。后来我在 AI 生成的基础上做了几处修改,比如用 p.stat().st_size 判断文件大小,超过 50MB 的文件就不再尝试提取正文,以免大 PDF 拖死进程。AI 一开始生成的版本没有这一步,我在测试时放了一个 1GB 的 PDF,它直接卡了十几分钟。这个限制加进去之后,全流程立马顺畅了。
3.2 三种常见文档的提取方式与踩坑点
AI 能很快给出 PDF、Word、Excel 的解析代码,但如果你完全照抄,到真实环境就很容易翻车。我把每种格式的提取逻辑都拆开讲一讲,因为它对应着不同文件格式的内部结构。
PDF 提取文本,我用的是 pypdf 里的 PdfReader。需要注意一点:PDF 分为“文本型 PDF”和“扫描型 PDF”。文本型 PDF 的每一页里有真正的文字数据,可以直接提取;扫描型 PDF 本质上是图片,提取出来只有空字符串,除非接 OCR。AI 生成的代码里如果没有做“空文本”判断,你会看到一大堆文件提取结果都是空白,还不报错。
python复制from pypdf import PdfReader
def extract_pdf_summary(path: Path):
try:
reader = PdfReader(str(path))
pages = len(reader.pages)
first_text = ""
for page in reader.pages[:3]:
content = page.extract_text() or ""
first_text += content.strip()
if len(first_text) > 200:
break
return {"pages": pages, "summary": first_text[:200]}
except Exception:
return {"pages": -1, "summary": "[PDF解析失败]"}
Word 的 docx 文件和 PDF 完全不同,它本质上是一个 zip 包,里面装着多个 XML 文件。python-docx 会帮我们解析这些 XML,取出段落文本。但要提醒的是,它默认解析的是 document.xml,如果文档里大多数内容放在页眉、页脚或表格里,段落提取的结果可能让人看不懂。
Excel 用 openpyxl 读取时,有一个常见问题:.xlsx 文件里有些工作表可能只是空壳,行列数会返回 1,而不是 0。AI 初次生成的代码没有处理这一点,导致提取结果里出现大量“某个 sheet 有 1 行 1 列”的假信息。我后来在代码里加了个判断:如果 sheet 的最大行号是 1 且最大列号是 1,再检查单元格内容是否为空,为空就直接标记为空表。这种细节绝不会出现在教材里,但处理真实文件时非常关键。
3.3 压缩包处理:文件名乱码是第一个拦路虎
我一开始只把 zip 当成“能解压就行”,结果 AI 生成的第一个版本在处理中文文件名时出现了乱码。原因很好解释:zip 格式的标准里,文件名编码早期用的是 CP437,后来很多 Windows 工具采用了本地编码如 GBK,而 Python 的 zipfile 模块在提取文件名时可能按 UTF-8 解码,要么报错,要么变成一片乱码。AI 生成代码时默认假设文件名是 UTF-8,可现实不是这样。
正确的应急策略是用 zipfile.ZipFile 读取每个文件的 filename,然后尝试几种编码,找到能正常解码的版本。一个简易的方法如下:
python复制def safe_decode_name(raw_name: str) -> str:
# 有些 zip 在生成时把文件名存成 gbk,需要手动转
for encoding in ("utf-8", "gbk", "big5"):
try:
return raw_name.encode("cp437").decode(encoding)
except Exception:
continue
return raw_name
这段代码是常用的“救火队员”。当然它不是完美方案,因为文件名编码不是从字符串本身一眼能看出的,只能通过尝试解码来判断。AI 不会主动想到这种情况,除非你在需求里专门提了“需要兼容中文 zip”。如果以后遇到更多压缩包编码问题,更稳妥的做法是先用 7-Zip 这种工具把 zip 重新压成 UTF-8 编码,或者直接改用 7z 命令行接口,但那是另一个题了。
3.4 把结果输出成 CSV,让非程序员也能用
工具最终是给同事和日常整理使用的,不是所有人都喜欢看命令行里的列表。所以输出端我让 AI 生成一个 CSV 导出函数。CSV 看似简单,但有一个很容易被 AI 忽略的坑:如果一个字段里本身包含逗号、换行或引号,你必须用 csv 模块来写入,而不是手动拼接字符串。
AI 一开始给我生成的代码是这种写法:
python复制# 这种写法是错的
line = f"{path},{size},{summary}\n"
一旦 summary 里有换行或逗号,整个 CSV 就崩了。后来我改成标准库 csv.DictWriter,每一个字段都会被正确转义。这是个非常好的例子,说明 AI 生成的代码在简单环境中看起来没问题,但实际数据一变复杂就露馅,所以最终校验还得靠人。
CSV 输出的文件字段设计如下,直接可作为通用的“文件索引清单”:
| 字段 | 说明 | 示例 |
|---|---|---|
| file_path | 文件完整绝对路径 | D:/资料/合同/2024-服务合同.pdf |
| file_ext | 文件扩展名,小写 | |
| file_size_kb | 文件大小,KB | 1024.5 |
| mtime | 最后修改时间 | 2025-06-01 10:30:00 |
| doc_type | 识别出的文档类型 | pdf / docx / xlsx / zip |
| detail_json | 与类型相关的额外信息 | |
| summary | 文本摘要,前200字 | 本合同由甲方... |
加一个 detail_json 字段,是为了让 CSV 保持兼容性。因为不同文档的额外属性差异太大,如果为每一种文件单独建一列,表格会宽得没法看。JSON 序列化进去,之后要做数据加工时再解析,很省事。
4. 文件提取开发过程中的问题排查与技巧实录
4.1 文件编码错位:不止出现在 zip 里
刚才提到 zip 文件名乱码,其实普通文本文件的编码问题更常见。很多老旧的 .txt 文件是 GBK 编码,而 Python 默认用 UTF-8 读取时,一读就抛 UnicodeDecodeError。如果脚本没有做异常捕获,整个批处理就会中断。我的解决方案是写一个 read_text_safely 函数,尝试读取时把编码范围放宽。
python复制def read_text_safely(path: Path, limit: int = 200):
raw = path.read_bytes()[:limit]
for enc in ("utf-8", "gbk", "latin-1"):
try:
return raw.decode(enc)
except UnicodeDecodeError:
continue
return raw.decode("utf-8", errors="replace")
别看 latin-1 这个编码很古老,它有一个特点:所有字节都能映射成字符,不会抛异常。所以当 UTF-8 和 GBK 都失败时,用 latin-1 兜底至少不会让整个脚本崩溃,然后再由人工决定如何处理。AI 不会主动想到这种编码阶梯,你必须自己测试后补充进代码里。
4.2 大文件会造成假死,必须设置文件大小上限
批处理最怕的不是某个文件解析失败,而是某个文件让程序彻底卡住。常见元凶是超大 PDF 或超大 zip。为了让工具不阻塞,我分别在遍历阶段和解析阶段都加了文件大小判断:
python复制MAX_PARSE_SIZE = 50 * 1024 * 1024 # 50MB
def should_parse_text(size: int) -> bool:
return size <= MAX_PARSE_SIZE
如果文件超过 50MB,就不提取正文摘要,只在 CSV 里留下一句“文件过大,跳过正文提取”。这个设计有一个实际好处:扫描全盘时能快速筛出大文件,把大文件单独列出来给人处理,而不是挂在脚本里等待。实测在几千个小文档目录下,任务能在几秒内完成;但一旦目录里混了几个几百 MB 的 CAD 压缩包,没有这个限制的话,脚本就会明显变慢。
4.3 被占用的文件或权限不足,要“软失败”而不是直接退出
Windows 环境下,经常遇到一个文件正在被 Word/WPS 打开,或者某个目录没有读取权限。Python 在读取时会抛 PermissionError,如果 AI 生成的代码没有在遍历层捕获,任务就中断了。
我实际的工程习惯是在最外层遍历时尽可能把“这个文件读不了”当成一种结果记录,而不是异常:
python复制for p in root_dir.rglob("*"):
try:
if p.is_file():
...
except PermissionError as e:
results.append({
"path": str(p),
"error": "权限不足",
})
这样最后导出的 CSV 里会看到一条条带有错误标记的记录,方便后续单独处理。这种“软失败”的容错方式,比简单 try/except 往日志里一扔更直观。AI 生成的初版代码通常只会在单文件解析函数里做异常处理,遍历层的权限问题它意识不到,必须靠运行到真实目录才会暴露。
4.4 重复文件扫描,给我最大的教训是“文件名不可靠”
我在整理归档时,经常以为两个文件名一模一样的 PDF 是重复文件,实际打开内容却完全不同;反过来,有些内容完全一样的文件,文件名却不一样。早期我把 AI 生成的提取工具当成了“文件查重器”,结果误报率很高。后来我增加了一个辅助函数:计算文件的 SHA-256 哈希,用来判断真正的内容重复。
核心思想是:如果文件的哈希值相同,那么内容几乎必然一致。然后我可以在 CSV 里增加一列 file_hash:
python复制import hashlib
def calc_sha256(path: Path, sample_limit: int = 1024 * 1024):
h = hashlib.sha256()
with open(path, "rb") as f:
while chunk := f.read(1024 * 1024):
h.update(chunk)
# 只读前 sample_limit 字节的话,需要手动控制逻辑
return h.hexdigest()
实际做全量哈希在大文件场景下会比较慢,所以我通常只对大小相同、修改时间也接近的文件做二次哈希校验。这一步是 AI 无法替我决策的,因为它不知道我关心的“重复”标准到底是什么。
4.5 日志:AI 生成代码时最不喜欢写的东西
AI 生成代码时非常反感写日志,因为它希望代码看起来精练。但在真实批处理任务里,没有日志几乎没法排查。我后来强制在每次遍历步骤里打印累计信息,形如:
text复制[2025-06-01 15:00:01] 已扫描 100 个文件,其中 PDF 40,Word 20,Excel 15,其他 25
[2025-06-01 15:00:04] 解析失败文件数:2,跳过原因见 errors.log
日志要写到两个地方:标准输出和 runtime.log。这样当工具在服务器上或深夜批量跑时,出了问题可以通过日志回溯,而不是一头雾水。说到底,AI 辅助开发的代码质量,很大程度上取决于你有没有提这些“不够酷但很实用”的工程要求。
5. AI 辅助开发的一些真实心得:哪些操作帮我省下了最多的返工
5.1 把任务拆成“子问题”喂给 AI,而不是一次性输入一个大需求
如果一开始就说“帮我写一个完整的文件管理系统”,AI 生成的结果往往会非常臃肿且不可维护。反过来,我这次的流程是拆成多个子任务,每完成一个就测试一个:
- 子任务一:遍历目录,输出文件基本属性。
- 子任务二:解析 PDF、Word、Excel,提取各自特有字段。
- 子任务三:解析压缩包,导出文件名清单,并实现安全解压。
- 子任务四:把所有结果写到 CSV,并生成一个可重复运行的入口函数。
每个子任务代码量控制在 100 行以内,运行结果清晰,出了问题也很容易定位。AI 辅助开发的一个常见误区,就是把它当成“写全栈项目”的工具,动辄要它一次生成几百行代码。代码越长,AI 幻觉率越高,各种上下文不一致就越明显。短小、单一、可验证,才是 AI 最擅长的模式。
5.2 让 AI 直接基于“真实样本”来调试,比描述更有效
有段时间我遇到一个非常隐蔽的 bug:某些 PDF 文件解析后取到的文本是一堆乱码,而且只发生在某个供应商提供的文件里。我想通过文字描述让 AI 定位问题,结果它给了十几种猜测,都没用。后来我把一个 PDF 样例复制到测试目录,然后让 AI 写一段“先打印 PDF 元数据和前 3 页原始字符”的诊断代码,才找到原因:那个 PDF 里的字体编码没有正确的 ToUnicode 映射,直接抽取文本就是乱码。
要诊断这类问题,你必须把样本文件本身暴露给工具,AI 才能看到真实环境。我发现 AI 辅助开发最重要的用法,不是“凭空写码”,而是“基于具体文件快速生成诊断脚本”。你给它一个糟糕的样本文件,它就能立刻生成对应的探测代码,比自己看 PDF 规范快得多。
5.3 学一点基础的正则和文件系统知识,能少被 AI 带偏
我虽然不要求每个人都成为 Python 高手,但如果你想让 AI 工具真正可用,至少要掌握两件事:pathlib.Path 的基本遍历方式和简单的正则表达式。因为文件提取工具里大量场景是对文件名做模式匹配,比如找出所有叫“合同”的 PDF、提取版本号、判断日期等。
我见过很多人让 AI 写正则,但自己完全看不懂,结果正则匹配错了也发现不了。比如常见的一个坑:在正则里没有把“.”转义,导致把所有文件名都匹配上了。AI 生成完正则后,你必须要求它给出几个测试用例,证明匹配逻辑符合预期。我后来会直接让 AI 输出“匹配样例”和“不匹配样例”,这样一眼就能判断它的逻辑是否正确。
5.4 这工具进化成了“系列工具箱”的开端
文件提取工具做完之后,我并没有停下来,而是用同样的方法做了一连串基于 AI 辅助的小工具,比如批量重命名、重复文件清理、自动归档分类。按照我现在的习惯,维护它们的方式不再是翻代码、改源码,而是把这个文件提取脚本当成基础模块,被其他脚本调用。比如归档分类工具会先读取 CSV 清单,再根据关键词把文件移动到对应文件夹。
后续我在考虑的一个扩展是:把这些工具打包成一个命令行入口 filekit,以后无论想提取、查重还是归档,只要敲一个命令就能完成。AI 辅助开发与手写代码的区别,并不在于代码多神奇,而是它把“从需求到原型”的时间压缩到了分钟级,让我能快速验证一个想法是否值得继续投入。如果一开始就手写整套代码,我可能还没跑起来就放弃了。
从个人体会讲,AI 辅助开发最核心的一点是逼着我把模糊的感受转化成清晰的需求。比如“想把文件整理一下”这种念头,最终被我拆成了“遍历哪些扩展名、提取什么属性、遇到异常怎么办、输出什么格式”。每拆一层,AI 能帮的忙就多一层。文件提取工具只是这个思维方式的第一个例子,后面一路做下来,返工次数也越来越少。如果你也想用类似思路处理手里那堆乱糟糟的文件,不妨先从一个测试目录、三个文件类型开始,跑通一轮后再扩大范围。这样即使 AI 生成代码出了小毛病,你也能很快发现,不至于面对几万行代码无从改起。
