用 Python 的 pathlib 与 os.scandir 写一个安全的文件批量重命名小工具
在日常工作中,批量重命名文件是一件看似简单、实则很容易出错的事情。比如整理下载目录、统一照片命名、给一批日志文件加上日期前缀,一次操作往往涉及几十甚至上百个文件。如果直接用一行循环加 os.rename 暴力改名,一旦中途遇到重名、权限不足或者路径写错,就可能出现文件被覆盖、改到一半无法回退的尴尬局面。本文介绍一个思路:用 Python 的 pathlib 与 os.scandir 写一个安全的小工具,核心是先预览、再执行,遇到冲突就跳过,全程留下日志。
一、为什么不用 os.listdir
很多教程里批量处理文件都用 os.listdir,它返回的是一个字符串列表,用起来确实方便,但有两个短板。第一,它只给名字,不给类型和元数据,想判断是文件还是目录、想取文件大小,还得再拼一次路径、再调一次 stat,目录大了就慢。第二,它把全部结果一次性装进内存,文件特别多时并不划算。
os.scandir 则返回一个迭代器,每一项都是 DirEntry 对象,自带 is_file、is_dir、stat 等方法,而且在多数系统上目录项的类型信息是随遍历一起返回的,不需要额外系统调用。配合 pathlib 的 Path 对象做路径拼接和改名,代码既清晰又不容易把斜杠拼错。
二、先定三条安全规则
在写代码之前,先把安全规则定下来,这比功能本身更重要。
第一,默认只预览不执行。工具必须有一个 dry-run 模式,而且应该是默认行为。只有当用户明确加上执行参数时,才真正改名。这样即使规则写错了,也只会多打印几行日志,不会动任何文件。
第二,目标已存在就跳过,绝不覆盖。重命名之前先判断目标路径是否存在,存在就记录一条跳过日志,继续处理下一个文件。不要用覆盖、不要自动加序号去猜用户意图,跳过是最保守、也最容易解释的行为。
第三,全程记日志。谁改了谁、谁被跳过、谁失败了,都要写进日志文件。日志是事后复核和回滚的唯一依据,建议同时输出到控制台和文件,日志里写清楚时间、原路径和目标路径。
三、核心代码
下面的示例把一批 txt 文件统一加上日期前缀,逻辑可以按需替换成自己的命名规则。
import logging
import os
from pathlib import Path
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s",
handlers=[logging.FileHandler("rename.log", encoding="utf-8"),
logging.StreamHandler()],
)
def iter_files(folder: Path):
with os.scandir(folder) as entries:
for entry in entries:
if entry.is_file() and entry.name.endswith(".txt"):
yield Path(entry.path)
def plan_rename(folder: Path, prefix: str):
plans = []
for src in iter_files(folder):
dst = src.with_name(prefix + src.name)
if dst.exists():
logging.warning("跳过:目标已存在 %s", dst)
continue
plans.append((src, dst))
return plans
def run(folder: Path, prefix: str, dry_run: bool = True):
plans = plan_rename(folder, prefix)
for src, dst in plans:
if dry_run:
logging.info("[预览] %s -> %s", src, dst)
continue
try:
src.rename(dst)
logging.info("已改名:%s -> %s", src, dst)
except OSError as exc:
logging.error("失败:%s,原因:%s", src, exc)
if __name__ == "__main__":
run(Path("./demo"), "2026-11-08_", dry_run=True)
这段代码有几个值得注意的细节。iter_files 用 os.scandir 做遍历,只挑文件、只挑 txt 后缀;plan_rename 先算好全部改名计划,顺手做冲突检查;run 负责执行,并且把每一次成功和失败都记下来。预览和执行共用同一份计划,这样预览时看到什么,执行时就是什么,不会出现预览一套、执行另一套的情况。
四、使用流程
建议的使用流程分四步。第一步,先在测试目录里放几个复制出来的样本文件,确认工具行为符合预期,再对真实目录动手。第二步,第一次运行保持 dry-run,逐行检查预览输出,重点看前缀、后缀和序号有没有拼错。第三步,确认无误后关掉 dry-run 真正执行,执行完立刻看日志里有没有失败记录。第四步,保留好日志文件,万一发现命名规则有问题,可以对照日志写一个反向脚本把名字改回去。
另外还有几点经验。不要直接在系统目录、云盘同步目录或者别人正在使用的目录里跑批量改名,先停掉可能占用这些文件的程序。文件名里不要出现系统保留字符,跨平台使用时尤其要注意 Windows 不允许的冒号、问号等字符。规则里如果涉及日期,建议用 YYYY-MM-DD 这种固定宽度格式,排序时才不会乱。
五、小结
批量重命名真正的难点从来不是怎么写循环,而是怎么在出错时不造成损失。pathlib 让路径操作更安全、更易读,os.scandir 让遍历更快、信息更全,而 dry-run 预览、冲突跳过和日志记录这三条规则,则是把一个随手写的脚本变成可以放心交给别人用的小工具的关键。先预览、再执行、留好日志,这套习惯同样适用于清理脚本、批量移动文件等其他高风险操作,值得在日常工作中坚持下去。
- 点赞
- 收藏
- 关注作者
评论(0)