用Python批量提取txt文件内容,自动生成目录索引文档

发布时间:2026/9/26 17:50:16
用Python批量提取txt文件内容,自动生成目录索引文档 大概一个月前朋友把他攒了多年的电子书和文档备份发给我说想整理出一份清单。我打开那个文件夹一看好家伙两千多个txt文件文件名从“笔记01”到随手打的“未命名168”都有。人肉一个个打开看根本不现实。我花了二十分钟写了个小脚本干的事核心就一句话提取txt文档名称和内容前N个字符生成新的目录文档。效果立竿见影——上午跑完下午他就能对着目录找东西了。这个需求听起来简单但处理文本时那些边边角角的问题折腾了我一下午才稳定下来。如果你也需要在大量txt文件里建立索引、做预览、整理语料这篇文章可以帮你少踩不少坑。下面这套代码和思路我用它处理过小说备份、论文资料、爬虫语料算是实测过很多轮了。1. 我的使用场景哪些人真的需要这个“txt目录生成器”1.1 资料归档与快速预览我接触到的第一类典型场景是个人资料归档。很多人的电脑里都有一堆txt读书笔记、摘抄、小说片段、工作日志时间一久文件名会变得毫无规律。与其一个个文件打开看不如生成一份目录文档把每个文件的名称、路径和内容摘要放在一张表里一眼扫过就知道这个文件大概是什么。这类用户通常不需要复杂的功能只要脚本能递归遍历文件夹把文档名称、路径、内容前N个字符按行输出到一个新文件里就够了。目录文档本身就是一个可搜索的索引配合VS Code或Notepad的多文件搜索效率能再翻倍。我朋友拿到目录后直接在编辑器里搜“龙族”“笔记”“合同”几秒钟就把需要的文件定位到了。1.2 语料筛选与数据集整理第二个场景是我自己遇到的。做自然语言处理或者准备微调数据时经常要快速判断一个语料文件是否符合要求。比如我想把一批小说txt转成统一的对话格式先得知道每个txt的开头长什么样。这时候如果手动去翻阅几百个文件就够人退缩了。用这个脚本把每个文件的内容前100个字符提取出来生成目录文档我就能在编辑器里用关键词筛选出“对话体”“第一人称”等特征先做一个粗糙的预筛再决定哪些文件进数据清洗流程。说白了它不是个成品工具而是整个数据流水线的第一道过滤器。目录文档帮忙省下的时间比我写脚本的时间多得多。1.3 内容合规检查与抽样还有一种你可能没想过的用法文本内容合规检查。比如从网上扒下来的一批txt可能有广告头、乱码头或者重复的免责声明。通过目录文档快速抽样开头马上能发现哪些文件头部是异常内容质量怎么样。甚至可以把脚本的参数改成N等于一个很大的值也就是提取全文输出成另一个清单用来做重复检测。当然这里要提醒一句大规模抓取和整理网络文本时务必注意版权问题个人使用和备份没问题但别拿去做传播。目录文档这个工具本身是中性的怎么用取决于你。2. 拆解核心逻辑文件名、前N个字符、目录文档这三件事2.1 目录文档应该长什么样在写代码之前先把需求拆成三个子问题找文件读内容写目录。目录文档的设计直接决定了后续好不好用。我推荐用制表符分隔的表格样式序号、文件相对路径、内容摘要三列。如果文件都在同一个目录下也可以只保留文件名但如果有多层子目录建议保存相对路径方便定位。实际效果类似这样序号 文件相对路径 内容前100个字符 1 ./books/龙族.txt 这是一个关于少年与龙的故事... 2 ./notes/机器学习笔记.txt 今天学完决策树终于理解了剪枝...制表符的好处是能被大多数编辑器和Excel无缝识别。如果你要长期维护这个目录我建议加一行表头并固定字段顺序后续写脚本解析也很轻松。不要把内容里的换行保留否则一行记录会变成多行整个表格结构瞬间乱掉。2.2 前N个字符的正确截取方式这里有个新手容易踩的坑“前N个字符”不等于“前N个字节”。在Python中用open()读取时给一个整数N比如f.read(100)是按Unicode字符读取的。中文、英文、标点都算一个字符这正好符合我们提取摘要的需求。但如果你在Linux下用head -c 100它就是按字节截取一个UTF-8汉字占3个字节所以100字节只能取到33个汉字左右还会截出半个字符。写脚本时一定要想清楚是按字符还是按字节。对于这个工具按字符最直观满足绝大多数场景。Python标准库直接按字符处理所以不用担心多字节编码的问题。2.3 遍历目录时需要注意的排序规则文件夹里的文件列表系统默认给的顺序往往不是按名称排列的尤其是Windows资源管理器里的“按名称排序”跟Python的sorted()字典序并不完全一样。比如文件“10.txt”会被排在“2.txt”前面因为字典序先比较第一个字符1小于2所以“10”会在“2”前面。这种细微差别在少量文件时无所谓但文件多了生成的目录文档顺序会显得很乱。我建议要么直接用os.walk拿到路径列表后做一下自然排序要么干脆不做排序按文件系统返回的顺序输出同时在目录文档里注明“顺序不代表优先级”。我的习惯是使用成熟的自然排序函数但为了不引入额外依赖简单方案是文件名按小写排序或者用正则提取数字前缀作为排序key。3. 手把手实现从零写一个可用的批处理脚本Python3.1 环境准备与整体代码结构先解释为什么用Python标准库就能处理文件遍历、读取和写入十几行代码搞定。下面的版本是我整理过的加入了基本的容错和参数交互你可以直接复制到本地运行。环境只需要Python 3.6以上不需要第三方库。脚本分四块路径处理、文件收集、内容提取、目录输出。核心不复杂重点是每一块都要考虑到真实世界里的脏数据。如果你连Python都没装去官网下载一个然后右键这个脚本用IDLE打开按F5就能跑非常简单。3.2 完整脚本与关键逻辑注释#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import sys import glob def collect_txt_files(root_dir, recursiveTrue): 收集目录下所有txt文件返回绝对路径列表 files [] if recursive: for root, dirs, filenames in os.walk(root_dir): for fn in filenames: if fn.lower().endswith(.txt): files.append(os.path.join(root, fn)) else: # 不递归只处理当前目录 pattern os.path.join(root_dir, *.txt) files glob.glob(pattern) # 按路径字符串排序保证输出相对稳定 files.sort(keylambda p: p.lower()) return files def read_head(file_path, n_chars): 读取文件前n个字符并清理换行等空白符号 text None # 依次尝试常见编码避免乱码 for encoding in (utf-8, gbk, latin-1): try: with open(file_path, r, encodingencoding) as f: text f.read(n_chars) break except UnicodeDecodeError: continue if text is None: return [编码无法识别] # 把换行、回车、制表符替换为空格避免目录行被截断 text text.replace(\r\n, ).replace(\r, ).replace(\n, ) text text.replace(\t, ).strip() return text def build_catalog(files, n_chars, root_dir): lines [] for idx, fp in enumerate(files, 1): rel os.path.relpath(fp, startroot_dir) head read_head(fp, n_chars) if head: lines.append(f{idx}\t{rel}\t{head}) else: lines.append(f{idx}\t{rel}\t[空文件或读取失败]) return lines def main(): root_dir input(请输入要扫描的目录路径留空为当前目录: ).strip() if not root_dir: root_dir os.getcwd() n_chars_str input(请输入要提取的字符数默认100: ).strip() n_chars int(n_chars_str) if n_chars_str.isdigit() else 100 files collect_txt_files(root_dir, recursiveTrue) if not files: print(该目录下没有txt文件退出。) return lines build_catalog(files, n_chars, root_dir) # 注意输出成.tsv而不是.txt避免被脚本自己扫描到 out_path os.path.join(root_dir, 目录文档.tsv) with open(out_path, w, encodingutf-8, errorsreplace) as f: f.write(序号\t文件相对路径\t内容前{}个字符\n.format(n_chars)) f.write(\n.join(lines)) print(f完成共提取 {len(files)} 个txt文件目录文档已写入 {out_path}) print(f内容摘要按每个文件的前 {n_chars} 个字符截取。) if __name__ __main__: main()几个关键点我要单独说一下collect_txt_files里用了os.walk会把子目录里的txt也搜出来适合整理嵌套很深的文件夹。如果你只需要当前目录一层把recursive改成False就行。read_head里尝试三种编码UTF-8覆盖大多数现代txtGBK覆盖Windows旧文件latin-1是兜底保证不会因为解码失败而中断整个目录生成。输出文件名用了目录文档.tsv这样脚本在下次运行时不会把这个目录文档本身当成待整理的文件避免了“目录里包含自己”的尴尬。3.3 配置N值和路径的小技巧我一般会把N值做成命令行参数而不是交互输入这样方便批量调用。比如python make_catalog.py --path D:\txts --num 200。如果你不想写argparse直接用sys.argv判断前两个参数就够了。另外N值的选择直接决定目录文档的可用性。经验值是100到200个字符100字符能表达大意的八分之一足够判断文件主题200字符更稳妥但文件数量超过一千时目录文档会膨胀到四五十万字符打开和搜索依然很流畅。如果只想看文件名N设成0就行等着一行行文件名列表。再说一个细节目录文档的输出路径默认放在扫描目录下如果输出后缀是.txt下次扫描时会被当成普通文本处理。我改用.tsv后缀以后想转Excel也方便。如果你坚持要.txt后缀至少要写一行排除逻辑把输出文件本身跳过。4. 实测中的四个坑编码、换行、超长文本和特殊文件名4.1 编码问题GBK与UTF-8的乱码战争这是我在实际测试中遇到的第一大坑。Windows下很多人用记事本保存的txt默认是GBK或ANSI编码而Linux和macOS下基本都是UTF-8。如果脚本只按UTF-8读取GBK文件轻则输出乱码重则直接报UnicodeDecodeError。我最初的脚本用的就是utf-8 errorsignore结果中文变成了一堆问号和乱码完全不可用。后来加了编码回退逻辑优先UTF-8解码失败再用GBK尝试最后用latin-1兜底。latin-1不会失败但会把字节直接映射成奇怪的字符至少能保留内容的原始结构方便后续修复。经验如果文件都是自己用Windows记事本创建的直接指定gbk反而更稳。更通用的做法是用chardet检测编码但那样会增加一个依赖。我这版脚本只靠标准库已经能满足大多数场景。如果你需要处理混合编码的目录建议先用记事本打开几个看看确定主力编码后改一下read_head里的顺序能更快得到干净结果。4.2 换行符和制表符把目录行搞乱了第二个坑是内容前N个字符里混着换行符。txt文件开头经常是空行或者标题换行如果原样写入目录文档一行记录就会变成多行整个表格结构瞬间乱掉。解决办法很简单在提取到文本后把换行、回车、制表符统一替换为空格。这里要注意顺序Windows的换行符是\r\n所以要先把\r\n替换成空格再单独处理\r和\n否则会出现两个空格。还可以顺便strip()去首尾空白。我还遇到过一种情况有些小说txt开头是连续多个空行导致提取出的摘要只有空白。这时可以在替换后判断strip结果是否为空如果是就标记为“文件开头为空”而不是让那行看起来像缺失数据。这样目录文档的每一行都有明确信息后续人工检查时心理负担小很多。4.3 特殊文件名空格、括号、Emoji和隐藏字符第三个坑是文件名本身。Windows文件名不允许反斜杠、冒号等但允许方括号、井号、中文、Emoji。这些字符在控制台和目录文档里都没问题但如果你把目录文档导入Excel某些字符可能会被识别成公式比如文件名以开头的文件。我的处理建议是目录文档里统一用相对路径代替纯文件名这样即使重名也不会丢信息如果文件名里包含超长路径Windows限制260字符脚本应该捕获路径超长的异常至少要打印出失败的路径。我自己碰到过一次某个txt文件名末尾有个不可见空格导致Python打印出来看起来正常但复制到其他地方找不到文件。所以最后还是坚持用相对路径作为唯一标识而不是只看文件名。目录文档里保留相对路径还有一个好处当你把整个文件夹打包压缩目录文档跟着一起走换个环境也能快速对应到原文件。4.4 当N值设得过大目录文档本身会爆炸最后一个坑比较隐蔽。如果你把N设成10000想多看些内容而且文件都是几十万字的小说脚本会读取每个文件的前一万字符生成超大的目录文档打开和搜索都会变慢。更合理的做法是设置上限如果文件总字符数小于N就只读全部如果大于N就读取前N。同时读取时最好用f.read(N)而不是f.read()再切片后者会把整个文件读入内存效率差很多。对于动辄几十MB的txt用read(n)才是正确姿势。另外提醒一句目录文档生成后最好别直接编辑保存不然下一次脚本重新扫描时会把你的备注也提取进去。我通常把目录文档.tsv当作快照备注写在另一个md文件里这样即使重新生成目录原来的备注也不会被覆盖。5. 进阶扩展从纯txt到目录文档的更多玩法5.1 按时间或大小过滤目录文档更干净第一个能立刻让脚本更实用的扩展是文件过滤。比如只提取最近修改的txt或者只提取大于10KB的文件避免把一堆只有几行的临时文件也收进来。实现也不复杂在collect_txt_files阶段增加条件判断os.path.getsize(fp) min_size或者用os.path.getmtime(fp)比较修改时间。按我的经验把过滤条件做成参数后目录文档的质量会高很多真正有用的是那些大文件小文本碎片通常可以直接排除。5.2 同时输出Markdown和CSV方便不同工具消费我现在生成目录文档时会同时输出两个版本一个.tsv给Excel和脚本用一个.md给GitHub、语雀这类平台渲染。好处是既能在编辑器里快速过滤也能放进在线文档直接阅读。Markdown格式其实很简单每一行写成- [序号] 文件路径摘要再加一个二级标题渲染出来就是漂亮的清单。如果后续想做成HTML也可以直接在脚本里套个模板把表格变成网页。我甚至试过把目录文档接入一个本地搜索页面输入关键词就能跳转对应txt文件但要额外处理路径转链接工作量不大比一个个翻文件舒服多了。5.3 联动关键词和正则让目录文档变成轻量检索引擎如果你对内容有明确的关键词需求比如只想找包含“龙族”或者“对话体”的txt可以在提取前N个字符后加一个判断用re.search把命中的文件单独输出一个分类目录。这样目录文档就具备了简单的检索能力。更进一步我还试过把所有txt开头和文件名拼成一个长字符串用正则做多关键词匹配然后输出一个命中清单。本质上和用文本编辑器搜索目录文档没有区别但脚本化之后可以定时跑适合每天新增文件的工作流。重命名文件也可以参考这个思路先扫描目录生成目录文档再根据目录里的摘要修改文件名做到内容和文件名统一。说实话这个脚本能跑通最耗费心力的不是十几行代码而是后面那几类边角料问题。我在给朋友跑数据时一开始生成出的目录里有乱码、有自己、也有被换行拆散的行修修改改才稳定下来。最后分享一个小建议第一版先固定N值比如100输出成.tsv跑通之后再加参数和过滤避免一上来就把需求想复杂。如果你手头也有一堆txt需要建立目录不妨从这份代码抄起。它可以帮你从“翻开文件夹茫然四顾”变成“打开目录文档一目了然”。后续想加什么功能欢迎留言聊我这边还有几个正在玩的变体比如按作者把小说生成多级目录、给每个txt自动生成一段摘要存成JSON有空继续写。