用 Python 的 pathlib 与 os.scandir 写一个安全的文件批量重命名小工具

举报
你永远是我的寶貝 发表于 2026/11/08 06:05:13 2026/11/08
【摘要】 用 Python 的 pathlib 与 os.scandir 写一个安全的文件批量重命名小工具:默认 dry-run 预览、目标已存在时跳过不覆盖、全程写日志,先预览再执行,避免批量改名出错造成损失。

在日常工作中,批量重命名文件是一件看似简单、实则很容易出错的事情。比如整理下载目录、统一照片命名、给一批日志文件加上日期前缀,一次操作往往涉及几十甚至上百个文件。如果直接用一行循环加 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 预览、冲突跳过和日志记录这三条规则,则是把一个随手写的脚本变成可以放心交给别人用的小工具的关键。先预览、再执行、留好日志,这套习惯同样适用于清理脚本、批量移动文件等其他高风险操作,值得在日常工作中坚持下去。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。