吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 183|回复: 4
上一主题 下一主题
收起左侧

[原创工具] 文件批量重命名工具(含修改后缀)

[复制链接]
跳转到指定楼层
楼主
ltzxd 发表于 2026-5-6 22:50 回帖奖励
本帖最后由 ltzxd 于 2026-5-6 13:54 编辑

如需成品自取:https://www.alipan.com/s/mPtY72SMuHo


功能:
1.跨文件夹批量选择修改文件名+后缀
2.修改后同步更新最初导入的文件名

3.防重复添加文件

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

class UltimateRenameTool:
    def __init__(self, root):
        self.root = root
        self.root.title("终极文件重命名工具 (跨文件夹追加版)")
        self.root.geometry("850x650") # 稍微调宽了一点以放下新按钮
        self.root.eval('tk::PlaceWindow . center')

        # 存储当前加载的文件信息
        self.file_items = []

        # 批量操作相关的变量
        self.old_str_var = tk.StringVar()
        self.new_str_var = tk.StringVar()
        self.new_ext_var = tk.StringVar()

        self.setup_ui()

    def setup_ui(self):
        # ================= 第一部分:文件选择 =================
        top_frame = tk.Frame(self.root)
        top_frame.pack(fill=tk.X, pady=10, padx=10)

        # 改为“追加选择”
        tk.Button(top_frame, text="📄 1. 追加选择需要修改的文件", command=self.select_files, bg="#e0f7fa", font=("微软雅黑", 10, "bold")).pack(side=tk.LEFT)
        # 新增:清空列表按钮
        tk.Button(top_frame, text="🗑️ 清空当前列表", command=self.clear_list, bg="#ffebee", font=("微软雅黑", 9)).pack(side=tk.LEFT, padx=10)
        
        self.status_label = tk.Label(top_frame, text="当前未选择任何文件", fg="#666666")
        self.status_label.pack(side=tk.LEFT, padx=10)

        # ================= 第二部分:批量操作面板 (预览更改) =================
        batch_frame = tk.LabelFrame(self.root, text="2. 批量快捷操作 (点击应用后将在下方预览,不会立即修改文件)", font=("微软雅黑", 9), padx=10, pady=10)
        batch_frame.pack(fill=tk.X, padx=15, pady=5)

        # 批量替换功能
        row1 = tk.Frame(batch_frame)
        row1.pack(fill=tk.X, pady=2)
        tk.Label(row1, text="批量替换名称中的:").pack(side=tk.LEFT)
        tk.Entry(row1, textvariable=self.old_str_var, width=12).pack(side=tk.LEFT, padx=5)
        tk.Label(row1, text="替换为:").pack(side=tk.LEFT)
        tk.Entry(row1, textvariable=self.new_str_var, width=12).pack(side=tk.LEFT, padx=5)
        tk.Button(row1, text="应用替换", command=self.apply_batch_replace, bg="#f5f5f5").pack(side=tk.LEFT, padx=10)

        # 批量修改后缀功能
        row2 = tk.Frame(batch_frame)
        row2.pack(fill=tk.X, pady=5)
        tk.Label(row2, text="批量修改后缀为 (如 .png):").pack(side=tk.LEFT)
        tk.Entry(row2, textvariable=self.new_ext_var, width=12).pack(side=tk.LEFT, padx=5)
        tk.Button(row2, text="应用新后缀", command=self.apply_batch_extension, bg="#f5f5f5").pack(side=tk.LEFT, padx=10)

        # ================= 第三部分:列表表头 =================
        header_frame = tk.Frame(self.root)
        header_frame.pack(fill=tk.X, padx=20, pady=(10, 0))
        tk.Label(header_frame, text="当前文件名 (左侧)", font=("微软雅黑", 9, "bold"), width=35, anchor='w').pack(side=tk.LEFT)
        tk.Label(header_frame, text="输入新的文件名 (右侧)", font=("微软雅黑", 9, "bold")).pack(side=tk.LEFT, padx=10)

        # ================= 第四部分:可滚动的列表区 =================
        list_container = tk.Frame(self.root, bd=1, relief=tk.SUNKEN)
        list_container.pack(fill=tk.BOTH, expand=True, padx=15, pady=5)

        self.canvas = tk.Canvas(list_container, highlightthickness=0)
        scrollbar = tk.Scrollbar(list_container, orient="vertical", command=self.canvas.yview)
        self.scrollable_frame = tk.Frame(self.canvas)

        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
        )

        self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        self.canvas.configure(yscrollcommand=scrollbar.set)

        self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # ================= 第五部分:执行按钮 =================
        bottom_frame = tk.Frame(self.root)
        bottom_frame.pack(fill=tk.X, pady=15)
        tk.Button(bottom_frame, text="&#9889; 3. 确认无误,执行真实修改", command=self.execute_rename, bg="#ffecb3", font=("微软雅黑", 11, "bold"), width=30).pack()


    # ---------------- 核心逻辑区 ----------------

    def select_files(self):
        """打开文件选择器,并将选中的文件 追加 到滚动列表中"""
        paths = filedialog.askopenfilenames(title="请按住 Ctrl 多选你要修改的文件 (可多次追加)")
        if not paths:
            return

        # 提取当前已经在列表里的旧路径,防止重复添加
        existing_paths = [item['old_path'] for item in self.file_items]
        added_count = 0

        # 渲染新选中的文件
        for path in paths:
            # 去重:如果文件已经在列表里,跳过
            if path in existing_paths:
                continue
                
            dir_name, file_name = os.path.split(path)
            
            row_frame = tk.Frame(self.scrollable_frame)
            row_frame.pack(fill=tk.X, pady=3, padx=5)

            # 左侧文字
            tk.Label(row_frame, text=file_name, width=40, anchor='w', fg="#333333").pack(side=tk.LEFT)

            # 右侧输入框
            new_name_var = tk.StringVar(value=file_name)
            entry = tk.Entry(row_frame, textvariable=new_name_var, width=45)
            entry.pack(side=tk.LEFT, padx=10)

            # 准备数据结构
            item_data = {
                'old_path': path,
                'new_name_var': new_name_var,
                'row_frame': row_frame
            }

            # 新增:剔除本行按钮
            btn_remove = tk.Button(row_frame, text="&#10060;", fg="red", relief=tk.FLAT, 
                                   command=lambda d=item_data: self.remove_item(d))
            btn_remove.pack(side=tk.LEFT, padx=5)

            # 加入全局列表
            self.file_items.append(item_data)
            added_count += 1

        self.update_status_label()

    def remove_item(self, item_data):
        """从列表中剔除单个文件"""
        # 销毁UI组件
        item_data['row_frame'].destroy()
        # 从数据列表中移除
        self.file_items.remove(item_data)
        self.update_status_label()

    def clear_list(self):
        """一键清空所有已选文件"""
        if not self.file_items:
            return
        if messagebox.askyesno("确认", "确定要清空当前所有已选择的文件吗?"):
            for item in self.file_items:
                item['row_frame'].destroy()
            self.file_items.clear()
            self.update_status_label()

    def update_status_label(self):
        """更新文件数量显示"""
        count = len(self.file_items)
        if count == 0:
            self.status_label.config(text="当前未选择任何文件")
        else:
            self.status_label.config(text=f"已加载 {count} 个文件")

    def apply_batch_replace(self):
        """将上方设置的替换规则,应用到右侧所有的输入框中(预览效果)"""
        old_str = self.old_str_var.get()
        new_str = self.new_str_var.get()
        if not old_str:
            messagebox.showinfo("提示", "请输入需要被替换的字符!")
            return
        
        for item in self.file_items:
            current_new_name = item['new_name_var'].get()
            updated_name = current_new_name.replace(old_str, new_str)
            item['new_name_var'].set(updated_name)

    def apply_batch_extension(self):
        """将上方设置的新后缀,应用到右侧所有的输入框中(预览效果)"""
        new_ext = self.new_ext_var.get().strip()
        if not new_ext:
            messagebox.showinfo("提示", "请输入新的后缀名,例如 .png 或 .txt")
            return
            
        if not new_ext.startswith("."):
            new_ext = "." + new_ext

        for item in self.file_items:
            current_new_name = item['new_name_var'].get()
            base_name, _ = os.path.splitext(current_new_name)
            item['new_name_var'].set(base_name + new_ext)

    def execute_rename(self):
        """遍历列表,将名称发生改变的文件进行真实的系统重命名"""
        if not self.file_items:
            messagebox.showwarning("提示", "列表为空,请先选择文件!")
            return

        success_count = 0
        error_messages = []

        for item in self.file_items:
            old_path = item['old_path']
            new_file_name = item['new_name_var'].get().strip()
            dir_name, old_file_name = os.path.split(old_path)

            if new_file_name == old_file_name or not new_file_name:
                continue

            new_path = os.path.join(dir_name, new_file_name)

            try:
                if os.path.exists(new_path) and new_path.lower() != old_path.lower():
                    error_messages.append(f"跳过: '{new_file_name}' 已存在。")
                    continue
                
                os.rename(old_path, new_path)
                
                item['old_path'] = new_path
                success_count += 1
                
            except Exception as e:
                error_messages.append(f"失败: '{old_file_name}' -> {str(e)}")

        # 为了避免重新选文件,修改成功后刷新列表展示的新老名字一致
        for item in self.file_items:
            _, current_name = os.path.split(item['old_path'])
            item['new_name_var'].set(current_name)
            # 更新左侧UI显示的标签
            for child in item['row_frame'].winfo_children():
                if isinstance(child, tk.Label):
                    child.config(text=current_name)
                    break

        if error_messages:
            error_text = "\n".join(error_messages[:5])
            if len(error_messages) > 5:
                error_text += "\n..."
            messagebox.showwarning("部分完成", f"成功修改 {success_count} 个文件。\n\n以下出现问题:\n{error_text}")
        elif success_count > 0:
            messagebox.showinfo("完成", f"&#127881; 成功修改 {success_count} 个文件!")
        else:
            messagebox.showinfo("提示", "没有检测到任何名称的更改。")

if __name__ == "__main__":
    root = tk.Tk()
    app = UltimateRenameTool(root)
    root.mainloop()

QQ20260506-233405.png (33.63 KB, 下载次数: 0)

QQ20260506-233405.png

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
chinawolf2000 + 1 + 1 热心回复!

查看全部评分

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

沙发
cai2532 发表于 2026-5-6 23:13
这个可以下载使用下
3#
Sako 发表于 2026-5-7 00:16
4#
jerrylee0521 发表于 2026-5-7 01:59
强烈推荐OncePower,功能强大又支持操作回退!
https://github.com/ilgnefz/once_power
5#
alanlyf 发表于 2026-5-7 03:34
感谢作者的分享,先收藏了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2026-5-7 04:59

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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