累计签到:16 天 连续签到:5 天
|
🔥 零学习成本・一键操作・支持回退🌟 工具亮点
超级简单:选文件夹 → 输前缀 → 点开始,三步搞定
自动规整:文件名自动按数字排序,长短不一也整齐
实时预览:改前改后看得见,避免改错
安全可撤回:自动保存记录,误操作一键恢复原名
干净无残留:日志自动隐藏,不污染文件夹
🚀 使用步骤(真・傻瓜式)
选择要重命名的文件夹
输入自定义前缀(默认:文件_)
切换排序方式 / 筛选文件类型(可选)
点击开始重命名,等待完成
如需恢复,点击撤销重命名即可
📋 功能说明
支持图片 / 视频 / 文档 / 表格 分类筛选
自动补全数字位数(01、001、0001)
文件夹内容变化实时同步更新
预览采用表格形式,清晰整洁
日志文件自动隐藏,永不参与重命名
下载地址:exe地址:rgbrgb[Python] 纯文本查看 复制代码import osimport tkinter as tkfrom tkinter import ttk, filedialog, messageboximport ctypesclass 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('', 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()<font color="#3f3f3f">rgb   |
精密测量技术论坛免责声明
✈️重要声明:以上内容仅代表该作者观点,不代表本站精密测量技术论坛立场。
✅如有涉及侵权请尽快告知,我们将会在第一时间处理。作者原创内容未经允许不得转载!
📱 站长联系邮箱:1339305021@qq.com
📱 站长联系微信:dddnnbbb
|