如需成品自取:
功能:
1.跨文件夹批量选择修改文件名+后缀
2.修改后同步更新最初导入的文件名
3.防重复添加文件
- 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="⚡ 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="❌", 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"🎉 成功修改 {success_count} 个文件!")
- else:
- messagebox.showinfo("提示", "没有检测到任何名称的更改。")
-
- if __name__ == "__main__":
- root = tk.Tk()
- app = UltimateRenameTool(root)
- root.mainloop()
复制代码

下载地址
© 版权声明
文章版权归作者所有,未经允许请勿转载。