吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 466|回复: 28
上一主题 下一主题
收起左侧

[原创工具] 傻瓜式批量重命名工具

[复制链接]
跳转到指定楼层
楼主
lck8 发表于 2026-3-25 12:28 回帖奖励
🔥 零学习成本・一键操作・支持回退🌟 工具亮点

  • 超级简单:选文件夹 → 输前缀 → 点开始,三步搞定

  • 自动规整:文件名自动按数字排序,长短不一也整齐

  • 实时预览:改前改后看得见,避免改错

  • 安全可撤回:自动保存记录,误操作一键恢复原名

  • 干净无残留:日志自动隐藏,不污染文件夹


🚀 使用步骤(真・傻瓜式)

  • 选择要重命名的文件夹

  • 输入自定义前缀(默认:文件_)

  • 切换排序方式 / 筛选文件类型(可选)

  • 点击开始重命名,等待完成

  • 如需恢复,点击撤销重命名即可
📋 功能说明

  • 支持图片 / 视频 / 文档 / 表格 分类筛选

  • 自动补全数字位数(01、001、0001)

  • 文件夹内容变化实时同步更新

  • 预览采用表格形式,清晰整洁

  • 日志文件自动隐藏,永不参与重命名
下载地址:exe地址:https://wwbpj.lanzouw.com/ifL863lhcaed密码:bpkz



[Python] 纯文本查看 复制代码
import os
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import ctypes

class BatchRenameApp:
    def __init__(self, root):
        self.root = root
        self.root.title("批量重命名工具")
        self.root.geometry("780x780")
        self.root.resizable(True, True)
        self.root.configure(bg="#f5f5f5")

        self.center_window()

        self.folder_path = tk.StringVar()
        self.prefix = tk.StringVar(value="文件_")
        self.sort_type = tk.StringVar(value="name")
        self.file_type = tk.StringVar(value="全部")
        self.file_list = []
        self.log_file = ".rename_log.txt"
        self.last_folder_mtime = 0

        self.setup_style()
        self.create_widgets()
        self.start_folder_monitor()

    def center_window(self):
        self.root.update_idletasks()
        w = self.root.winfo_width()
        h = self.root.winfo_height()
        x = (self.root.winfo_screenwidth() // 2) - (w // 2)
        y = (self.root.winfo_screenheight() // 2) - (h // 2)
        self.root.geometry(f"{w}x{h}+{x}+{y}")

    def setup_style(self):
        style = ttk.Style()
        style.theme_use('clam')
        style.configure('Modern.TButton', font=('微软雅黑', 10), background="#4285F4", foreground="white", padding=8)
        style.map('Modern.TButton', background=[('active', '#3367D6')])
        style.configure('Modern.TLabel', font=('微软雅黑', 10), background="#f5f5f5")
        style.configure('Title.TLabel', font=('微软雅黑', 16, 'bold'), background="#f5f5f5", foreground="#202124")
        style.configure('TRadiobutton', font=('微软雅黑', 10), background="#f5f5f5")
        style.configure("Treeview.Heading", font=('微软雅黑', 10, 'bold'))
        style.configure("Treeview", font=('微软雅黑', 10), rowheight=25)

    def create_widgets(self):
        title_label = ttk.Label(self.root, text="批量重命名工具", style="Title.TLabel")
        title_label.pack(pady=20)

        folder_frame = tk.Frame(self.root, bg="#f5f5f5")
        folder_frame.pack(fill=tk.X, padx=30, pady=6)
        ttk.Label(folder_frame, text="目标文件夹:", style="Modern.TLabel").pack(side=tk.LEFT)
        self.folder_entry = ttk.Entry(folder_frame, textvariable=self.folder_path, font=('微软雅黑', 10), width=45)
        self.folder_entry.pack(side=tk.LEFT, padx=10)
        ttk.Button(folder_frame, text="选择文件夹", command=self.select_folder, style='Modern.TButton').pack(side=tk.LEFT)

        prefix_frame = tk.Frame(self.root, bg="#f5f5f5")
        prefix_frame.pack(fill=tk.X, padx=30, pady=6)
        ttk.Label(prefix_frame, text="文件前缀:", style="Modern.TLabel").pack(side=tk.LEFT)
        prefix_entry = ttk.Entry(prefix_frame, textvariable=self.prefix, font=('微软雅黑', 10), width=30)
        prefix_entry.pack(side=tk.LEFT, padx=10)
        prefix_entry.bind('<KeyRelease>', lambda e: self.update_preview())

        sort_frame = tk.Frame(self.root, bg="#f5f5f5")
        sort_frame.pack(fill=tk.X, padx=30, pady=6)
        ttk.Label(sort_frame, text="排序方式:", style="Modern.TLabel").pack(side=tk.LEFT, padx=0)
        ttk.Radiobutton(sort_frame, text="按名称", variable=self.sort_type, value="name", command=self.load_files).pack(side=tk.LEFT, padx=8)
        ttk.Radiobutton(sort_frame, text="按修改时间", variable=self.sort_type, value="mtime", command=self.load_files).pack(side=tk.LEFT, padx=8)

        type_frame = tk.Frame(self.root, bg="#f5f5f5")
        type_frame.pack(fill=tk.X, padx=30, pady=6)
        ttk.Label(type_frame, text="文件类型:", style="Modern.TLabel").pack(side=tk.LEFT, padx=0)
        ttk.Radiobutton(type_frame, text="全部", variable=self.file_type, value="全部", command=self.load_files).pack(side=tk.LEFT, padx=6)
        ttk.Radiobutton(type_frame, text="图片", variable=self.file_type, value="图片", command=self.load_files).pack(side=tk.LEFT, padx=6)
        ttk.Radiobutton(type_frame, text="视频", variable=self.file_type, value="视频", command=self.load_files).pack(side=tk.LEFT, padx=6)
        ttk.Radiobutton(type_frame, text="文档", variable=self.file_type, value="文档", command=self.load_files).pack(side=tk.LEFT, padx=6)
        ttk.Radiobutton(type_frame, text="表格", variable=self.file_type, value="表格", command=self.load_files).pack(side=tk.LEFT, padx=6)

        info_frame = tk.Frame(self.root, bg="#f5f5f5")
        info_frame.pack(fill=tk.X, padx=30, pady=6)
        self.file_count_label = ttk.Label(info_frame, text="文件数量:0 个", style="Modern.TLabel")
        self.file_count_label.pack(side=tk.LEFT)

        # 表格预览区
        preview_frame = tk.LabelFrame(self.root, text="重命名预览", font=('微软雅黑', 11, 'bold'), bg="#f5f5f5", padx=10, pady=10)
        preview_frame.pack(fill=tk.BOTH, expand=True, padx=30, pady=10)

        self.preview_tree = ttk.Treeview(preview_frame, columns=("原文件名", "新文件名"), show="headings", height=12)
        self.preview_tree.heading("原文件名", text="原文件名")
        self.preview_tree.heading("新文件名", text="新文件名")
        self.preview_tree.column("原文件名", width=380, anchor=tk.W)
        self.preview_tree.column("新文件名", width=280, anchor=tk.W)
        scrollbar = ttk.Scrollbar(preview_frame, orient=tk.VERTICAL, command=self.preview_tree.yview)
        self.preview_tree.config(yscrollcommand=scrollbar.set)
        self.preview_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        btn_frame = tk.Frame(self.root, bg="#f5f5f5")
        btn_frame.pack(pady=20)
        ttk.Button(btn_frame, text="开始重命名", command=self.start_rename, style='Modern.TButton').pack(side=tk.LEFT, padx=10)
        ttk.Button(btn_frame, text="撤销重命名", command=self.undo_rename, style='Modern.TButton').pack(side=tk.LEFT, padx=10)
        ttk.Button(btn_frame, text="清空重置", command=self.clear_all, style='Modern.TButton').pack(side=tk.LEFT, padx=10)

    # 文件夹监控
    def start_folder_monitor(self):
        self.check_folder_change()

    def check_folder_change(self):
        folder = self.folder_path.get()
        if os.path.isdir(folder):
            current_mtime = os.path.getmtime(folder)
            if current_mtime != self.last_folder_mtime:
                self.last_folder_mtime = current_mtime
                self.load_files()
        self.root.after(2000, self.check_folder_change)

    # 排除日志文件
    def match_file_type(self, filename):
        if filename == self.log_file:
            return False
        ext = os.path.splitext(filename)[1].lower()
        ftype = self.file_type.get()
        image = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp']
        video = ['.mp4', '.mov', '.avi', '.mkv', '.flv', '.wmv', '.rmvb']
        doc = ['.doc', '.docx', '.txt', '.pdf', '.ppt', '.pptx']
        excel = ['.xls', '.xlsx', '.csv']
        if ftype == "全部":
            return True
        elif ftype == "图片":
            return ext in image
        elif ftype == "视频":
            return ext in video
        elif ftype == "文档":
            return ext in doc
        elif ftype == "表格":
            return ext in excel
        return False

    def select_folder(self):
        path = filedialog.askdirectory(title="选择文件夹")
        if path:
            self.folder_path.set(path)
            self.last_folder_mtime = os.path.getmtime(path)
            self.load_files()

    def load_files(self):
        folder = self.folder_path.get()
        if not os.path.isdir(folder):
            return
        self.file_list = []
        for name in os.listdir(folder):
            fp = os.path.join(folder, name)
            if os.path.isfile(fp) and self.match_file_type(name):
                self.file_list.append(name)
        if self.sort_type.get() == "name":
            self.file_list.sort()
        else:
            self.file_list.sort(key=lambda x: os.path.getmtime(os.path.join(folder, x)))
        self.file_count_label.config(text=f"文件数量:{len(self.file_list)} 个")
        self.update_preview()

    def get_num_format(self, count):
        if count < 10:
            return "{:01d}"
        elif count < 100:
            return "{:02d}"
        elif count < 1000:
            return "{:03d}"
        else:
            return "{:04d}"

    # 表格预览
    def update_preview(self):
        for item in self.preview_tree.get_children():
            self.preview_tree.delete(item)
        if not self.file_list:
            return
        prefix = self.prefix.get()
        count = len(self.file_list)
        fmt = self.get_num_format(count)
        for i, name in enumerate(self.file_list, 1):
            ext = os.path.splitext(name)[1]
            new_name = f"{prefix}{fmt.format(i)}{ext}"
            self.preview_tree.insert("", tk.END, values=(name, new_name))

    # =================== 修复权限报错的核心代码 ===================
    def start_rename(self):
        folder = self.folder_path.get()
        if not os.path.isdir(folder):
            messagebox.showerror("错误", "请先选择文件夹")
            return
        if not self.file_list:
            messagebox.showwarning("提示", "没有可重命名的文件")
            return

        prefix = self.prefix.get()
        count = len(self.file_list)
        fmt = self.get_num_format(count)
        log_path = os.path.join(folder, self.log_file)

        if not messagebox.askyesno("确认", f"即将重命名 {count} 个文件,是否继续?"):
            return

        # 先取消隐藏,解决权限问题
        try:
            ctypes.windll.kernel32.SetFileAttributesW(log_path, 0)
        except:
            pass

        rename_records = []
        ok = 0
        ng = 0
        for i, name in enumerate(self.file_list, 1):
            old_path = os.path.join(folder, name)
            ext = os.path.splitext(name)[1]
            new_name = f"{prefix}{fmt.format(i)}{ext}"
            new_path = os.path.join(folder, new_name)
            try:
                if os.path.exists(new_path):
                    new_path = os.path.join(folder, f"temp_{fmt.format(i)}{ext}")
                os.rename(old_path, new_path)
                rename_records.append(f"{name}|{new_name}")
                ok += 1
            except:
                ng += 1

        # 写入日志
        with open(log_path, 'w', encoding='utf-8') as f:
            f.write("\n".join(rename_records))

        # 重新设置隐藏
        try:
            ctypes.windll.kernel32.SetFileAttributesW(log_path, 2)
        except:
            pass

        messagebox.showinfo("完成", f"重命名完成!\n成功:{ok} 个\n失败:{ng} 个")
        self.load_files()
    # ==============================================================

    def undo_rename(self):
        folder = self.folder_path.get()
        log_path = os.path.join(folder, self.log_file)

        if not os.path.exists(log_path):
            messagebox.showerror("错误", "未找到重命名记录,无法撤销!")
            return

        if not messagebox.askyesno("确认", "确定要恢复所有文件的原始名称吗?"):
            return

        try:
            with open(log_path, 'r', encoding='utf-8') as f:
                lines = [l.strip() for l in f.readlines() if l.strip()]
        except:
            messagebox.showerror("错误", "记录文件读取失败")
            return

        ok = 0
        ng = 0
        for line in lines:
            if "|" not in line:
                continue
            old_name, new_name = line.split("|", 1)
            new_path = os.path.join(folder, new_name)
            old_path = os.path.join(folder, old_name)
            try:
                if os.path.exists(new_path):
                    os.rename(new_path, old_path)
                    ok += 1
            except:
                ng += 1

        messagebox.showinfo("完成", f"撤销完成!\n成功恢复:{ok} 个\n失败:{ng} 个")
        self.load_files()

    def clear_all(self):
        self.folder_path.set("")
        self.prefix.set("文件_")
        self.sort_type.set("name")
        self.file_type.set("全部")
        self.file_list = []
        self.last_folder_mtime = 0
        self.file_count_label.config(text="文件数量:0 个")
        for item in self.preview_tree.get_children():
            self.preview_tree.delete(item)

if __name__ == "__main__":
    app = tk.Tk()
    window = BatchRenameApp(app)
    app.mainloop()

633e4b26-e894-4394-a6eb-7b43bd2a525c.png (53.01 KB, 下载次数: 0)

633e4b26-e894-4394-a6eb-7b43bd2a525c.png

2.png (64.79 KB, 下载次数: 0)

2.png

ScreenShot_2026-03-25_122547_923.png (26.76 KB, 下载次数: 0)

ScreenShot_2026-03-25_122547_923.png

免费评分

参与人数 5吾爱币 +9 热心值 +5 收起 理由
yanjh1 + 1 谢谢@Thanks!
foxeroil + 1 好评
zhangwei6929 + 1 + 1 谢谢@Thanks!
qsj521521 + 1 + 1 热心回复!
风之暇想 + 7 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
Ouroboross 发表于 2026-3-26 09:50
支持.就撤回这一项 在日常工作中 算是最基本的,但好多重命名的都没有这一功能.难道是我比较容易出错的原因吗,哈哈
推荐
qsl1037 发表于 2026-3-26 15:16
感谢分享,小工具很好用,提个建议:重命名预览框里可以调整文件的顺序,以及可以删除文件让它不参与重命名。
沙发
少狼 发表于 2026-3-25 22:39
3#
morty9531 发表于 2026-3-25 22:51
感谢lz分享
4#
phoebusor 发表于 2026-3-26 08:00
好东西,感谢分享!!!!
5#
荷塘夜色 发表于 2026-3-26 08:54
我用的重命名软件不多,但能撤销的只见到了这一个。不错不错
6#
gemini8 发表于 2026-3-26 09:15
谢谢楼主分享
7#
hgdkt87 发表于 2026-3-26 09:37
谢谢分享!
9#
LWHV587 发表于 2026-3-26 10:00
我这种手颤党的福音
10#
wstcdw123 发表于 2026-3-26 10:31
一看就明白了怎么操作,感谢分享!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-3-26 18:18

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表