# Python实现本地文件批量重命名GUI工具:解放你的双手


背景介绍

你是否曾面对几十个甚至上百个文件,需要手动修改名称?比如旅行照片要统一加上日期前缀,工作文档要按序号排列,手动重命名不仅耗时还容易出错。今天,我们将用Python和Tkinter打造一个轻量级批量重命名工具,支持灵活规则配置、实时预览和一键执行,彻底解决这个痛点。

思路分析

要实现这个工具,我们需要拆解核心功能并对应技术方案:
1. 文件夹选择:用Tkinter的filedialog弹出文件夹选择对话框;
2. 规则配置:通过输入框和复选框收集用户设置(前缀/后缀、序号、替换、日期);
3. 预览功能:遍历文件夹文件,根据规则生成新名称,用列表框展示对比结果;
4. 执行重命名:调用os.rename批量修改文件名,捕获异常统计成功率;
5. 结果反馈:用messagebox显示成功/失败数量及详情。

代码实现

我们选择Tkinter作为GUI框架(内置无需额外安装),结合os处理文件系统、datetime处理日期。以下是完整可运行代码:

import tkinter as tk
from tkinter import filedialog, messagebox
import os
from datetime import datetime

# 全局变量存储预览结果(原路径, 新路径)
preview_list = []

def select_folder():
    """选择目标文件夹"""
    folder = filedialog.askdirectory()
    if folder:
        entry_folder.delete(0, tk.END)
        entry_folder.insert(0, folder)

def preview():
    """生成重命名预览结果"""
    global preview_list
    preview_list.clear()
    list_preview.delete(0, tk.END)

    folder_path = entry_folder.get().strip()
    if not folder_path or not os.path.isdir(folder_path):
        messagebox.showwarning("警告", "请选择有效的文件夹!")
        return

    # 获取规则参数
    prefix = entry_prefix.get().strip()
    suffix = entry_suffix.get().strip()

    try:
        seq_start = int(entry_seq_start.get().strip())
        seq_digits = int(entry_seq_digits.get().strip())
    except ValueError:
        messagebox.showwarning("警告", "序号起始和位数必须为整数!")
        return

    keep_name = var_keep_name.get()
    use_replace = var_replace.get()
    old_str = entry_old_str.get().strip()
    new_str = entry_new_str.get().strip()
    use_date = var_date.get()
    date_format = entry_date_format.get().strip() if use_date else ""

    # 遍历文件夹中的文件(排除子文件夹)
    files = [f for f in os.listdir(folder_path) if os.path.isfile(os.path.join(folder_path, f))]
    if not files:
        messagebox.showinfo("提示", "文件夹中无文件!")
        return

    files.sort()  # 按文件名排序
    seq_num = seq_start

    for filename in files:
        name, ext = os.path.splitext(filename)
        date_part = ""

        # 处理日期插入
        if use_date:
            try:
                date_part = datetime.now().strftime(date_format)
            except Exception as e:
                messagebox.showwarning("警告", f"日期格式错误:{str(e)}")
                return

        # 处理名称部分(原文件名/序号)
        name_part = ""
        if keep_name:
            temp_name = name
            if use_replace and old_str:
                temp_name = temp_name.replace(old_str, new_str)
            name_part = temp_name
        else:
            name_part = str(seq_num).zfill(seq_digits)

        # 组合新文件名
        new_filename = f"{prefix}{date_part}{name_part}{suffix}{ext}"
        if not new_filename:
            messagebox.showwarning("警告", f"生成空文件名:{filename}")
            continue

        # 构建路径
        old_path = os.path.join(folder_path, filename)
        new_path = os.path.join(folder_path, new_filename)

        preview_list.append((old_path, new_path))
        list_preview.insert(tk.END, f"{filename} → {new_filename}")
        seq_num +=1

    messagebox.showinfo("提示", f"预览完成,共{len(files)}个文件")

def execute_rename():
    """执行批量重命名"""
    if not preview_list:
        messagebox.showwarning("警告", "请先预览结果!")
        return

    if not messagebox.askyesno("确认", "确定执行?此操作不可撤销!"):
        return

    success = 0
    fail = 0
    fail_details = []

    for old_path, new_path in preview_list:
        try:
            os.rename(old_path, new_path)
            success +=1
        except Exception as e:
            fail +=1
            fail_details.append(f"{os.path.basename(old_path)}: {str(e)}")

    # 显示结果
    result = f"成功:{success} | 失败:{fail}\n"
    if fail >0:
        result += "失败详情:\n" + "\n".join(fail_details)
    messagebox.showinfo("结果", result)
    preview()  # 刷新预览

# -------------------------- 主界面构建 --------------------------
root = tk.Tk()
root.title("批量文件重命名工具")
root.geometry("850x650")

# 文件夹选择区域
tk.Label(root, text="目标文件夹:").grid(row=0, column=0, padx=5, pady=5, sticky="w")
entry_folder = tk.Entry(root, width=70)
entry_folder.grid(row=0, column=1, padx=5, pady=5, sticky="we")
tk.Button(root, text="选择", command=select_folder).grid(row=0, column=2, padx=5, pady=5)

# 规则配置区域
# 前缀/后缀
tk.Label(root, text="前缀:").grid(row=1, column=0, padx=5, pady=5, sticky="w")
entry_prefix = tk.Entry(root, width=20)
entry_prefix.grid(row=1, column=1, padx=5, pady=5, sticky="w")

tk.Label(root, text="后缀:").grid(row=1, column=2, padx=5, pady=5, sticky="w")
entry_suffix = tk.Entry(root, width=20)
entry_suffix.grid(row=1, column=3, padx=5, pady=5, sticky="w")

# 序号设置
tk.Label(root, text="序号起始:").grid(row=2, column=0, padx=5, pady=5, sticky="w")
entry_seq_start = tk.Entry(root, width=5)
entry_seq_start.grid(row=2, column=1, padx=5, pady=5, sticky="w")
entry_seq_start.insert(0, "1")

tk.Label(root, text="序号位数:").grid(row=2, column=2, padx=5, pady=5, sticky="w")
entry_seq_digits = tk.Entry(root, width=5)
entry_seq_digits.grid(row=2, column=3, padx=5, pady=5, sticky="w")
entry_seq_digits.insert(0, "3")

# 保留原文件名
var_keep_name = tk.BooleanVar()
tk.Checkbutton(root, text="保留原文件名(不含后缀)", variable=var_keep_name).grid(row=3, column=0, padx=5, pady=5, sticky="w", columnspan=2)

# 字符串替换
var_replace = tk.BooleanVar()
tk.Checkbutton(root, text="字符串替换", variable=var_replace).grid(row=4, column=0, padx=5, pady=5, sticky="w")
tk.Label(root, text="旧字符串:").grid(row=4, column=1, padx=5, pady=5, sticky="w")
entry_old_str = tk.Entry(root, width=20)
entry_old_str.grid(row=4, column=2, padx=5, pady=5, sticky="w")
tk.Label(root, text="新字符串:").grid(row=4, column=3, padx=5, pady=5, sticky="w")
entry_new_str = tk.Entry(root, width=20)
entry_new_str.grid(row=4, column=4, padx=5, pady=5, sticky="w")

# 日期插入
var_date = tk.BooleanVar()
tk.Checkbutton(root, text="插入日期", variable=var_date).grid(row=5, column=0, padx=5, pady=5, sticky="w")
tk.Label(root, text="日期格式(如%Y-%m-%d):").grid(row=5, column=1, padx=5, pady=5, sticky="w")
entry_date_format = tk.Entry(root, width=20)
entry_date_format.grid(row=5, column=2, padx=5, pady=5, sticky="w")
entry_date_format.insert(0, "%Y-%m-%d")

# 预览区域
tk.Button(root, text="预览结果", command=preview).grid(row=6, column=0, padx=5, pady=10, sticky="w")
list_preview = tk.Listbox(root, width=100, height=18)
list_preview.grid(row=7, column=0, padx=5, pady=5, columnspan=5, sticky="we")
scrollbar = tk.Scrollbar(root, orient="vertical", command=list_preview.yview)
scrollbar.grid(row=7, column=5, sticky="ns")
list_preview.config(yscrollcommand=scrollbar.set)

# 执行按钮
tk.Button(root, text="执行重命名", command=execute_rename, bg="#4CAF50", fg="white", padx=10, pady=5).grid(row=8, column=0, padx=5, pady=10, sticky="w")

root.mainloop()

代码解释

  1. 界面构建:使用Tkinter的grid布局组织组件,包括文件夹选择区、规则配置区、预览区和执行按钮。
  2. 文件夹选择:通过filedialog.askdirectory获取用户选择的文件夹路径。
  3. 规则处理
    • 前缀/后缀:直接拼接在名称前后;
    • 序号:支持起始值和补零位数;
    • 保留原文件名:可选是否保留原名称(不含后缀);
    • 字符串替换:对原文件名进行指定字符串替换;
    • 日期插入:用datetime生成指定格式的日期字符串。
  4. 预览功能:遍历文件夹文件,根据规则生成新名称并展示对比结果,避免误操作。
  5. 执行重命名:调用os.rename批量修改文件,捕获异常并统计结果。

总结

这个工具通过简单的GUI界面实现了灵活的批量重命名功能,涵盖了文件操作、字符串处理和事件驱动编程等核心知识点。你可以基于此扩展更多功能:
– 支持正则表达式替换;
– 自定义规则顺序;
– 保存/加载常用规则;
– 处理子文件夹中的文件。

希望这个工具能帮你节省时间,也希望你能从代码中学到实用的Python技能!
“`


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注