python 批量重命名工具

点击查看代码
import os
import pandas as pd
import tkinter as tk
from tkinter import ttk, filedialog, messagebox


# --------------- 核心功能函数(移除自动加序号,报错定位问题)---------------
def batch_rename_files(excel_path, file_folder, log_text):
    """
   通用批量重命名核心函数(支持所有文件类型,移除自动加序号,报错定位问题)
   :param excel_path: Excel文件路径
   :param file_folder: 文件文件夹路径
   :param log_text: 日志显示文本框
   """
    log_text.delete(1.0, tk.END)  # 清空日志

    try:
        # 第一步:建立「双重映射表」(移除图片后缀限制,处理所有文件)
        log_text.insert(tk.END, "🔍 正在扫描文件文件夹...\n")
        log_text.update()
        file_mapping = {}
        for file_name in os.listdir(file_folder):
            # 跳过文件夹,只处理文件
            file_full_path = os.path.join(file_folder, file_name)
            if os.path.isdir(file_full_path):
                continue
            # 为所有文件建立映射(支持带后缀/不带后缀匹配)
            file_mapping[file_name] = file_name
            file_name_no_ext = os.path.splitext(file_name)[0]
            file_mapping[file_name_no_ext] = file_name

        # 第二步:读取Excel表格
        log_text.insert(tk.END, "📖 正在读取Excel文件...\n")
        log_text.update()
        df = pd.read_excel(excel_path, header=None, engine="openpyxl")
        process_results = []

        # 第三步:遍历表格处理(移除自动加序号,直接重命名)
        log_text.insert(tk.END, "🚀 开始批量重命名...\n")
        log_text.insert(tk.END, "------------------------\n")
        log_text.update()

        for idx, (_, row) in enumerate(df.iterrows(), 1):
            original_name = str(row[0]).strip() if pd.notna(row[0]) else ""
            new_name_no_ext = str(row[1]).strip().replace(".0", "") if pd.notna(row[1]) else ""

            if not original_name or not new_name_no_ext:
                process_results.append("跳过")
                log_text.insert(tk.END, f"⏭️ 第{idx}行:数据为空,跳过\n")
                continue

            if original_name in file_mapping:
                original_full_name = file_mapping[original_name]
                original_path = os.path.join(file_folder, original_full_name)
                ext = os.path.splitext(original_full_name)[1]  # 自动获取原文件后缀
                new_full_name = f"{new_name_no_ext}{ext}"
                new_path = os.path.join(file_folder, new_full_name)  # 移除自动加序号

                # 直接重命名,不处理重复(重复会触发异常)
                os.rename(original_path, new_path)
                process_results.append("成功")
                log_text.insert(tk.END, f"✅ 第{idx}行:{original_full_name} → {os.path.basename(new_path)}\n")
            else:
                process_results.append("失败")
                log_text.insert(tk.END, f"⚠️ 第{idx}行:未找到对应文件({original_name})\n")
            log_text.update()

        # 补全结果列表并写入Excel
        while len(process_results) < len(df):
            process_results.append("无数据")
        df[2] = process_results
        df.to_excel(excel_path, index=False, header=None, engine="openpyxl")

        # 结果统计与提示
        log_text.insert(tk.END, "------------------------\n")
        log_text.insert(tk.END, f"📝 处理结果已写入Excel C列!\n")
        log_text.insert(tk.END, f"🎉 批量重命名完成!共处理{len(df)}行数据\n")
        success_count = process_results.count("成功")
        fail_count = process_results.count("失败")
        skip_count = process_results.count("跳过")
        log_text.insert(tk.END, f"📊 统计:成功{success_count} | 失败{fail_count} | 跳过{skip_count}\n")
        messagebox.showinfo("成功", f"批量重命名完成!\n成功:{success_count} | 失败:{fail_count} | 跳过:{skip_count}")

    except FileExistsError as e:
        # 专门捕获文件重名错误,精准提示
        error_msg = f"文件重名无法重命名:{str(e)},请检查Excel中B列的新文件名是否重复!"
        log_text.insert(tk.END, f"❌ 错误:{error_msg}\n")
        messagebox.showerror("重名错误", error_msg)
    except FileNotFoundError as e:
        error_msg = f"文件未找到:{str(e)},请检查Excel A列的原文件名是否正确!"
        log_text.insert(tk.END, f"❌ 错误:{error_msg}\n")
        messagebox.showerror("文件不存在", error_msg)
    except PermissionError:
        error_msg = "权限不足/文件被占用!请检查:1.文件是否被打开 2.是否以管理员身份运行 3.文件夹是否有写入权限"
        log_text.insert(tk.END, f"❌ 错误:{error_msg}\n")
        messagebox.showerror("权限/占用错误", error_msg)
    except Exception as e:
        error_msg = f"处理出错:{str(e)},请根据错误信息排查问题!"
        log_text.insert(tk.END, f"❌ 错误:{error_msg}\n")
        messagebox.showerror("未知错误", error_msg)


# --------------- Tkinter界面函数(无修改)---------------
def select_excel_file(entry):
    """选择Excel文件并填充到输入框"""
    file_path = filedialog.askopenfilename(
        title="选择Excel文件",
        filetypes=[("Excel文件", "*.xlsx"), ("所有文件", "*.*")]
    )
    if file_path:
        entry.delete(0, tk.END)
        entry.insert(0, file_path)


def select_file_folder(entry):
    """选择文件文件夹并填充到输入框(通用命名)"""
    folder_path = filedialog.askdirectory(title="选择文件文件夹")
    if folder_path:
        entry.delete(0, tk.END)
        entry.insert(0, folder_path)


def start_process(excel_entry, folder_entry, log_text):
    """开始处理按钮的回调函数"""
    excel_path = excel_entry.get().strip()
    file_folder = folder_entry.get().strip()

    # 验证路径
    if not excel_path:
        messagebox.warning("提示", "请先选择Excel文件!")
        return
    if not file_folder:
        messagebox.warning("提示", "请先选择文件文件夹!")
        return
    if not os.path.exists(excel_path):
        messagebox.warning("提示", "选择的Excel文件不存在!")
        return
    if not os.path.exists(file_folder):
        messagebox.warning("提示", "选择的文件文件夹不存在!")
        return

    # 执行通用重命名
    batch_rename_files(excel_path, file_folder, log_text)


# --------------- 主界面搭建(无修改)---------------
def create_main_window():
    root = tk.Tk()
    root.title("通用文件批量重命名工具(支持PDF/Word/Excel/图片等)")
    root.geometry("800x700")
    root.resizable(True, True)

    # 样式配置
    style = ttk.Style(root)
    style.configure("TLabel", font=("微软雅黑", 10))
    style.configure("TButton", font=("微软雅黑", 10))
    style.configure("TEntry", font=("微软雅黑", 10))
    style.configure("Warning.TLabel", font=("微软雅黑", 10, "bold"), foreground="#D83A56")
    style.configure("Accent.TButton", font=("微软雅黑", 10, "bold"), foreground="black", background="#E0E0E0")

    # 1. Excel文件选择区域
    ttk.Label(root, text="Excel文件路径:").grid(
        row=0, column=0, padx=10, pady=10, sticky="w"
    )
    excel_entry = ttk.Entry(root, width=60)
    excel_entry.grid(row=0, column=1, padx=5, pady=10, sticky="we")
    ttk.Button(
        root, text="选择文件",
        command=lambda: select_excel_file(excel_entry)
    ).grid(row=0, column=2, padx=5, pady=10)

    # 2. 文件文件夹选择区域(通用命名)
    ttk.Label(root, text="文件文件夹路径:").grid(
        row=1, column=0, padx=10, pady=10, sticky="w"
    )
    folder_entry = ttk.Entry(root, width=60)
    folder_entry.grid(row=1, column=1, padx=5, pady=10, sticky="we")
    ttk.Button(
        root, text="选择文件夹",
        command=lambda: select_file_folder(folder_entry)
    ).grid(row=1, column=2, padx=5, pady=10)

    # 先定义log_text(修复变量作用域)
    ttk.Label(root, text="处理日志:").grid(
        row=5, column=0, padx=10, pady=5, sticky="w"
    )
    log_text = tk.Text(root, width=90, height=20, font=("微软雅黑", 9))
    log_scroll = ttk.Scrollbar(root, orient="vertical", command=log_text.yview)
    log_text.configure(yscrollcommand=log_scroll.set)
    log_text.grid(row=6, column=0, columnspan=2, padx=10, pady=5, sticky="nsew")
    log_scroll.grid(row=6, column=2, padx=0, pady=5, sticky="ns")

    # 3. 开始处理按钮
    ttk.Button(
        root, text="开始批量重命名", style="Accent.TButton",
        command=lambda: start_process(excel_entry, folder_entry, log_text)
    ).grid(row=2, column=0, columnspan=3, pady=20)

    # 4. 注意事项区域(适配通用文件)
    ttk.Label(root, text="⚠️ 注意事项", style="Warning.TLabel").grid(
        row=3, column=0, columnspan=3, padx=10, pady=(0, 5), sticky="w"
    )
    notice_text = tk.Text(root, width=90, height=4, font=("微软雅黑", 9), bg="#F8F9FA", state="disabled")
    notice_text.grid(row=4, column=0, columnspan=3, padx=10, pady=(0, 10), sticky="we")
    notice_text.configure(state="normal")
    notice_content = """1. Excel表格A列:填写需要重命名的文件原文件名(支持带后缀如"报告1.pdf" 或 不带后缀如"报告1")
2. Excel表格B列:填写文件的新文件名(仅需名称,不要带后缀!程序会自动继承原文件的.pdf/.docx/.xlsx等后缀)
3. 处理完成后,Excel表格C列会自动写入「成功/失败/跳过」(执行时关闭Excel,避免占用)
4. 若新文件名重复会直接报错,请确保B列新文件名无重复!"""  # 新增重名提示
    notice_text.insert(tk.END, notice_content)
    notice_text.configure(state="disabled")

    # 调整列/行权重
    root.grid_columnconfigure(1, weight=1)
    root.grid_rowconfigure(6, weight=1)

    return root


# --------------- 程序入口 ---------------
if __name__ == "__main__":
    main_window = create_main_window()
    main_window.mainloop()

image

posted @ 2026-01-21 15:45  卜郝纪  阅读(0)  评论(0)    收藏  举报