资讯动态

Python自动化整理个人文档库:脚本批量重命名与分类实践

发布时间:2026/10/15 6:58:44 来源:尧图企业网站定制
今天这篇学习日记day74我想从一个很小但很真实的痛点说起个人文档库的混乱。我坚持写了七十多天的技术笔记到第50天左右的时候积累的Markdown文件、临时记录、代码片段已经散落得到处都是文件名千奇百怪比如“新建文档123.md”、“未命名2222.txt”、“最终版最终版V3.md”。第74天我决定不再逃避这个问题用一上午的时间写了一个Python脚本把整堆散乱的笔记自动归类、重命名、去重顺手还生成了一份目录索引。整个过程不算复杂但踩了不少坑也把很多平时没想明白的细节彻底搞清楚了。这篇日记就记录一下当天的完整思路、代码和问题排查过程想给同样被文件整理折磨的朋友一个可以直接抄作业的参考。如果你是刚开始接触自动化脚本的新手或者你手里也有一堆命名混乱的文档不知道从何下手这篇内容会比较适合你。我会尽量把每一步的原理讲明白而不是只丢一段代码让你复制。1. 今天的学习目标与选题拆解1.1 第74天这个节点的特殊意义连续写了74天学习日记其实是一个挺微妙的状态。前30天是新鲜感驱动的每天学什么都觉得有意思到第60天左右新鲜感消退开始进入一种需要靠习惯和真实产出维持的阶段。这个时候如果继续零零散散地学新知识学习效果反而会打折因为积累的东西没有系统化很多内容学了就忘了需要的时候又找不到。所以我在第74天给自己定了一个不一样的目标不是学新东西而是用已有的知识去解决一个具体问题。整理文档这件事既需要文件操作能力又需要正则表达式知识还需要对数据结构有一点理解——正好把我前七十多天学的内容串起来了。我打算用python写一个脚本把我那个乱糟糟的知识笔记目录彻底整理一遍。1.2 先搞清楚要解决什么问题动手前我没有急着写代码先花了不少时间盘了盘自己的文档库里到底有什么。不查不知道一查吓一跳一个不到两GB的目录里挤着400多个文件分布在8层深浅不一的子文件夹里有十几种文件格式。我把问题归纳成四类命名完全没有规则日期、编号、中文、英文、表情符号混在一起看不出哪个文件是关于什么主题的大量重复文件同一个笔记被导出多次内容相似文件名带“副本”、“最终版”这类标记文件类型混杂markdown笔记、txt草稿、PDF资料、代码文件堆在同一个目录里找东西全靠记忆没有索引想看自己写过哪些专题内容只能一个个文件翻这些问题其实很有代表性。很多人日常整理文件时用的是“新建文件夹”和“手动移动”的办法因为怕搞错所以不敢动结果越积越多最后干脆放弃整理。第74天我把手动整理拟成的备份只考虑“自动识别分类”和“批量重命名”这两个动作让脚本干那些重复机械的活。1.3 为什么用脚本而不是现成工具可能有人会问现在不是有很多文件整理工具、笔记软件自带的归档功能吗为什么不直接拿来用。我的回答是现成工具确实省事但有两个问题没法绕开。第一工具只解决它自己定义好的场景。比如笔记软件可以给文件打标签但如果你的文件有一半是txt、PDF还有源码文件大杂烩式的目录根本不是某个单一软件能覆盖的。第二我想借这个机会练手。用脚本整理的最大价值是你必须理清“文件的特征怎么识别”、“重命名的规则怎么定”、“哪些文件需要保留”这个过程本身就是一次系统性的思考训练。从性价比看写一个百来行的Python脚本一次投入时间以后每次产生新笔记都可以跑一遍长期节省的时间和精力远超手动整理。所以我确定方案遍历目录、识别文件类型和主题关键词、按规则重命名、按分类移入对应文件夹、生成索引。这就是这次学习日记的完整目标。2. 动手前必须理解的核心原理2.1 文件名背后的信息结构整理文件的第一个核心认知是文件名不只是给人看的它本质上是一条信息记录。一段好的文件名应该一句话就能说清“这是什么内容、什么时间、属于哪个主题”。我当时给自己定了一个命名模板主题_日期_说明.扩展名。比如python_oop_20240418_类继承笔记.md一眼就能看出这段笔记的主题、记录时间和内容概要。这个模板看着简单但落地的时候有几个细节要考虑。第一日期格式要统一。中文里习惯写“2024年4月18日”但在文件名里最好用20240418这种紧凑格式因为带年、月、日三个字符的文件名在排序时会乱掉“年”和“月”是中文编码顺序不直观。第二主题词要控制在两三个以内不能太长否则文件名失去快速扫读的意义。第三扩展名必须保留不能改动这是系统识别文件类型的关键。实际写脚本的时候主题词并不是我想出来的而是从原文件名和正文内容里提取的。这就涉及到第二个核心概念——正则表达式。2.2 正则表达式从一团文字里捞关键词如果你第一次接触正则表达式不用怕它的思想其实很简单定义一套规则让程序按规则在文本里找匹配的内容。我打个比方正则表达式就像一张带孔的面具你把面具往文字堆上一贴只有形状刚好对的文字能露出头来其他都被挡住。这个“形状”就是你自己定义的匹配模式。我用到的正则功能其实很基础一个是匹配固定的字符模式比如\d{8}能匹配8位连续数字恰好用来识别日期另一个是按字符类别匹配比如\.md$能判断一个文件名是不是以.md结尾的拿来做文件类型分类还有一个是替换捕获内容把匹配到的部分提取出来变成我要的命名结果。在标题的场景里正则表达式的容错设计很关键。文档名称里经常有各种奇怪的字符、空格、中文标点如果规则写得过于严格就会漏掉一批文件写得太宽松又可能把不该匹配的内容卷进来。我的策略是先用一个“比较保守”的匹配规则跑一遍把能识别的文件先整理出来识别不了的清单留在日志里再根据日志给文件补一个默认分类。这是后面实操过程中反复用到的思路。2.3 批量操作的安全边界永远先跑演练模式在讲代码之前我必须先强调一个血的教训批量操作类脚本绝对不能一上来就对原始文件动手。我当时把“操作前先演练”当作铁律任何移动、改名、删改动作都先在一个副本目录或者虚拟模式下试运行确认无误了才针对真实文件执行。你可以把“演练”理解成一次只输出日志不执行动作的跑法。脚本遍历所有文件、计算目标位置和文件名打印出来一行行检查但就是不真正移动文件。这一步能防住八成以上的低级错误。另外无论运行什么脚本第一步永远是全量备份。我用了一个很简单的方法把原始目录压缩成一个带时间戳的zip包放到其他盘里。这句话看起来像废话但真的有人不备份就直接跑批量脚本结果出现意外时哭都来不及。3. 实操过程与核心代码实现3.1 环境准备脚本运行环境很轻量一台装了Python 3.8以上版本的电脑就行。我用到的库有三个os遍历文件和目录、re正则表达式匹配、shutil移动文件。这三个都是Python自带的标准库不需要任何第三方依赖也不会因为环境问题跑不起来。这样做的考虑是一个工具如果依赖一大堆额外安装别人想复现时就会在环境上卡住我用最基础的标准库把门槛降到最低。在项目目录E:\learning_notes下我建了一个脚本文件organize_notes.py还按整理后的结构设计好了目标文件夹md_notes放Markdown笔记text_notes放TXT文件pdf_docs放PDF资料code_snippets放代码文件others放暂时无法归类的文件。3.2 核心代码遍历、识别、重命名、移动我的第一版脚本大致长这样import os import re import shutil from datetime import datetime ROOT_DIR rE:\learning_notes DATE_PATTERN re.compile(r(\d{8})|(\d{4})[-_.](\d{1,2})[-_.](\d{1,2})) TYPE_MAP { .md: md_notes, .txt: text_notes, .pdf: pdf_docs, } def extract_date_from_name(filename): 从文件名中提取日期返回yyyyMMdd格式字符串提取不到则返回日期未知 match DATE_PATTERN.search(filename) if not match: return date_unknown if match.group(1): return match.group(1) year, month, day match.group(2), match.group(3), match.group(4) return f{year}{month.zfill(2)}{day.zfill(2)} def build_new_name(filename, category, date_str, tag): 按照 主题_日期_说明.扩展名 的结构生成新文件名 stem, ext os.path.splitext(filename) tag tag or 未分类 safe_date date_str return f{tag}_{safe_date}_{stem}_整理.{ext}这段代码的思路是这样DATE_PATTERN负责从文件名里扒出日期支持20240418和2024-04-18两种格式TYPE_MAP是文件类型到目标文件夹的映射build_new_name把提取到的信息组合成一个带“整理”标记的新文件名避免和可能存在的重名文件冲突。接下来是遍历目录、执行移动的主逻辑。我在这里特意加入了一个dry_run参数也就是前面说的演练模式。传入True时只打印将要做什么传False时才真正执行操作。def organize(root_path, dry_runTrue): for current_dir, _, files in os.walk(root_path): for filename in files: file_path os.path.join(current_dir, filename) if file_path os.path.abspath(__file__): continue # 跳过脚本自身 ext os.path.splitext(filename)[1].lower() category TYPE_MAP.get(ext, others) date_str extract_date_from_name(filename) new_name build_new_name(filename, category, date_str) target_dir os.path.join(root_path, category) target_path os.path.join(target_dir, new_name) if dry_run: print(f[演练] {file_path} - {target_path}) else: os.makedirs(target_dir, exist_okTrue) if not os.path.exists(target_path): shutil.move(file_path, target_path) if __name__ __main__: organize(ROOT_DIR, dry_runTrue)如果你第一次跑这个脚本建议先调用organize(ROOT_DIR, dry_runTrue)把所有重命名和移动计划打印出来过目一遍。确认无误后再把参数改成False正式执行。这个习惯我到现在都保留着它帮我挡掉了不知道多少次误操作。3.3 一次真实运行的效果比对我那天正式执行前先跑演练模式发现一个问题大量文件的日期没有被正确提取全都变成了date_unknown导致文件名里出现了很多“未分类_日期未知”的组合。这个结果虽然不好看但很有价值它暴露了原始文件不用标准日期格式的严重程度。我随机抽了十几条日志检查发现主要有三种情况一是有文件名写的是“2024年4月18日”中文年月日我的正则没认出来二是日期藏在文件内容第一行文件名里根本没有三是完全没有日期信息比如“临时想法.txt”。针对这个问题我加了一段辅助逻辑当文件名提取不到日期时从文件内容的前五行里用同样的正则再去摘一下日期。如果还是找不到再考虑用文件的创建时间作为兜底。def extract_date_from_content(file_path): 从文件前几行内容中尝试提取日期 try: with open(file_path, r, encodingutf-8, errorsignore) as f: head .join(f.readlines()[:5]) except Exception: return match DATE_PATTERN.search(head) if not match: return # 逻辑与extract_date_from_name类似此处省略重复实现 return date_str重新跑完演练模式后正确识别日期的比例从不足三成提升到了八成以上效果非常明显。正式跑了一遍脚本原来400多个文件被整齐地分到了5个分类目录里文件名也全部统一成了主题_日期_说明_整理.扩展名的格式。整理完那一刻我打开文件管理器看着新的目录结构那种顺滑感是真真切切让人上瘾的。3.4 顺带解决重复文件的问题重复文件这个问题我单独写了一个小模块来处理。思路很简单对候选文件计算一个简单的哈希值把哈希值相同的文件挑出来保留命名最规范的那一个其他的移到一个duplicates_suspect文件夹里不直接删除。这里我刻意选择了“移动而非删除”原因有两个一是哈希值相同的文件内容可能只是部分相同比如同一个笔记的不同版本不能断言内容完全冗余二是人检查比脚本判断可靠“疑似重复”这个状态本身就已经足够提醒我人工确认一次了。当天的实测结果是从400多个文件里找出了32个可疑重复项人工确认后真正可以安全清理的有25个左右。这个比例不算小也从侧面说明了日常笔记管理里“随手复制一份”这个习惯带来的浪费有多严重。4. 当天踩过的坑与排查过程实录4.1 第一个坑中文文件名乱码首批正式跑脚本我遇到的头号问题是中文文件名乱码。我日常用的是Windows系统很多历史文件是早期从别的地方拷贝过来的文件名本身是正常的简体中文但用Python读取时部分文件名变成了乱码。排查思路是这样的先确认是不是脚本读取错误于是单独打印了几个乱码文件名的字节表示。结果发现os.listdir()返回的文件名其实是正常的只是控制台输出时因为编码设置不对显示成了乱码。我改用把日志写入文件的方式去查看乱码现象消失了。但这还没完。真正的问题在移动文件时部分目标路径因为包含特殊字符而找不到文件。我后来排查发现是源文件的文件名里包含了Windows不允许的字符比如?和*这些字符在系统层面已经被替换但脚本用同名去操作时就容易出错。最终我加了过滤逻辑新文件名只保留中文、英文、数字、下划线和连字符其余全部替换成下划线。4.2 第二个坑日期提取规则误伤文件名另一个坑比较隐蔽。我的正则规则里用\d{8}去匹配8位连续数字结果把某些文件名里的类似“20231201_会议纪要”的部分给拆错了。更离谱的是有个文件名是“程序员必须知道的100个问题”里面没有数字日期但“100”被当成三位数字干扰匹配吗不会因为规则要求8位连续数字所以没有误伤。真正的问题出在另一条规则上日期格式支持2024-04-18而文件名里像“小红书-2023-笔记”这种带分隔符的文本会把“2023”单独提取出来当作年份。排查时我用了一段小而独立的测试脚本把目录里所有文件名逐一打印出来对照正则匹配结果才定位到问题。我调整了匹配策略只有在上下文同时满足“月份在1-12、日期在1-31”时才认定为日期否则跳过。这里的教训是正则表达式的威力恰恰在于它的精确可控保持规则严格但不过度需要反复校验边界条件。4.3 第三个坑执行到一半报找不到目标目录正式执行时脚本跑到第112个文件的时候突然报错目标目录不存在。我检查代码发现我在move之前其实已经用os.makedirs(target_dir, exist_okTrue)创建了目录但这个调用是在循环内部、且带条件的如果某个分类的目录先被意外创建而后续路径写错了就会出现问题。更细看其实是同一个脚本里有两处创建目录的逻辑其中一处少加了exist_okTrue另一处则会覆盖掉之前设定的分类名导致目标路径不一样。这个问题花了我快二十分钟才定位出来。解决方法是统一封装一个ensure_dir()函数所有创建目录的地方都走同一个入口并且把分类名的映射表写成一个全局常量保证任何地方引用都是同一个值。现在想想如果一开始把代码写得模块化一点就不至于调试这么久。4.4 常见问题排查速查表当天结束后我把踩过的坑整理成一张速查表方便以后自查遇到的现象可能的根因排查思路解决办法文件名显示乱码控制台输出编码不一致把输出改为写入日志文件观察设置输出编码为UTF-8日志用文件记录目标路径找不到文件名含特殊符号或映射不统一打印实际路径和异常栈过滤特殊字符统一封装目录创建逻辑日期全部是unknown文件名格式不标准无日期字段抽样打印文件名和匹配结果增加从文件内容提取日期的兜底逻辑移动后文件缺失移动目标已存在同名文件检查是否skip或覆盖对目标文件名做唯一性检查加序号后缀4.5 两个价值很高的避坑心得第一个心得是关于备份的。前七天我差点直接对原始目录跑脚本因为当时的“演练”输出看起来非常完美没有报错。但就在正式跑之前我鬼使神差地先把整个目录压缩备份了一份。等到执行到中途报错尝试各种修复办法都没有让所有文件移动成功时我才真正理解备份的价值——它让我们在出问题时永远有回头路。第二个心得是关于小步迭代的。与其写一个超大的脚本一次性解决所有问题不如把任务拆成“先分类再重命名最后查重”三个独立步骤每完成一步就检查一遍结果。我第一次就是把所有逻辑揉在一个主函数里导致出错后要在一百多行代码里找漏洞效率极低。改用小步骤之后后面再跑任何批量脚本我都遵循这个“分阶段验证”的原则。5. 这次整理带来的蝴蝶效应第74天整理完文档之后当天的收获其实已经超出了脚本本身。我开始重新审视自己做学习笔记的方式后续在每一天的学习日记里都先把新产生的笔记按统一模板命名放进对应分类不再让文档积压成山。这个习惯坚持到现在我的笔记库再没有重新陷入混乱过。另一个意外收获是这次脚本里写的“正则表达式匹配日期”的方法被我复制到了别的地方用。比如我手头有一些按日期命名的日志文件要批量分析直接就拿这个函数改一改省了很多事。所以说很多学习项目的价值不只是解决眼下的某个问题它会像一个工具箱以后遇到类似场景时自动产生复用价值。那天下午我重新打开整理过的笔记目录把几个月来想写但一直没理清楚的几个专题一口气梳理了出来。因为我能在五秒内定位到任何一条过去的笔记知识之间的连接一下子变得更加清晰。这种体验让我觉得花一个上午写那个整理脚本可能是第74天做出得最有价值的一个决定。如果你也想动手整理自己的文档库我的建议是第一步不要追求完美先做一次演练和备份把文件按类型分开第二步再慢慢统一命名规则第三步才考虑去重和内容索引。脚本越简单越好能用标准库就不用第三方依赖。过程中出问题时多想想“这个异常信息在告诉我什么”而不是急着去网上找现成答案。这样跑完一遍你学到的会比任何一篇教程都多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑