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

实用软件1周前更新 小编
4 0

如需成品自取:

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

  1. import os
  2. import tkinter as tk
  3. from tkinter import filedialog, messagebox
  4. class UltimateRenameTool:
  5.     def __init__(self, root):
  6.         self.root = root
  7.         self.root.title("终极文件重命名工具 (跨文件夹追加版)")
  8.         self.root.geometry("850x650") # 稍微调宽了一点以放下新按钮
  9.         self.root.eval('tk::PlaceWindow . center')
  10.         # 存储当前加载的文件信息
  11.         self.file_items = []
  12.         # 批量操作相关的变量
  13.         self.old_str_var = tk.StringVar()
  14.         self.new_str_var = tk.StringVar()
  15.         self.new_ext_var = tk.StringVar()
  16.         self.setup_ui()
  17.     def setup_ui(self):
  18.         # ================= 第一部分:文件选择 =================
  19.         top_frame = tk.Frame(self.root)
  20.         top_frame.pack(fill=tk.X, pady=10, padx=10)
  21.         # 改为“追加选择”
  22.         tk.Button(top_frame, text="📄 1. 追加选择需要修改的文件", command=self.select_files, bg="#e0f7fa", font=("微软雅黑", 10, "bold")).pack(side=tk.LEFT)
  23.         # 新增:清空列表按钮
  24.         tk.Button(top_frame, text="🗑️ 清空当前列表", command=self.clear_list, bg="#ffebee", font=("微软雅黑", 9)).pack(side=tk.LEFT, padx=10)
  25.          
  26.         self.status_label = tk.Label(top_frame, text="当前未选择任何文件", fg="#666666")
  27.         self.status_label.pack(side=tk.LEFT, padx=10)
  28.         # ================= 第二部分:批量操作面板 (预览更改) =================
  29.         batch_frame = tk.LabelFrame(self.root, text="2. 批量快捷操作 (点击应用后将在下方预览,不会立即修改文件)", font=("微软雅黑", 9), padx=10, pady=10)
  30.         batch_frame.pack(fill=tk.X, padx=15, pady=5)
  31.         # 批量替换功能
  32.         row1 = tk.Frame(batch_frame)
  33.         row1.pack(fill=tk.X, pady=2)
  34.         tk.Label(row1, text="批量替换名称中的:").pack(side=tk.LEFT)
  35.         tk.Entry(row1, textvariable=self.old_str_var, width=12).pack(side=tk.LEFT, padx=5)
  36.         tk.Label(row1, text="替换为:").pack(side=tk.LEFT)
  37.         tk.Entry(row1, textvariable=self.new_str_var, width=12).pack(side=tk.LEFT, padx=5)
  38.         tk.Button(row1, text="应用替换", command=self.apply_batch_replace, bg="#f5f5f5").pack(side=tk.LEFT, padx=10)
  39.         # 批量修改后缀功能
  40.         row2 = tk.Frame(batch_frame)
  41.         row2.pack(fill=tk.X, pady=5)
  42.         tk.Label(row2, text="批量修改后缀为 (如 .png):").pack(side=tk.LEFT)
  43.         tk.Entry(row2, textvariable=self.new_ext_var, width=12).pack(side=tk.LEFT, padx=5)
  44.         tk.Button(row2, text="应用新后缀", command=self.apply_batch_extension, bg="#f5f5f5").pack(side=tk.LEFT, padx=10)
  45.         # ================= 第三部分:列表表头 =================
  46.         header_frame = tk.Frame(self.root)
  47.         header_frame.pack(fill=tk.X, padx=20, pady=(10, 0))
  48.         tk.Label(header_frame, text="当前文件名 (左侧)", font=("微软雅黑", 9, "bold"), width=35, anchor='w').pack(side=tk.LEFT)
  49.         tk.Label(header_frame, text="输入新的文件名 (右侧)", font=("微软雅黑", 9, "bold")).pack(side=tk.LEFT, padx=10)
  50.         # ================= 第四部分:可滚动的列表区 =================
  51.         list_container = tk.Frame(self.root, bd=1, relief=tk.SUNKEN)
  52.         list_container.pack(fill=tk.BOTH, expand=True, padx=15, pady=5)
  53.         self.canvas = tk.Canvas(list_container, highlightthickness=0)
  54.         scrollbar = tk.Scrollbar(list_container, orient="vertical", command=self.canvas.yview)
  55.         self.scrollable_frame = tk.Frame(self.canvas)
  56.         self.scrollable_frame.bind(
  57.             "<Configure>",
  58.             lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))
  59.         )
  60.         self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
  61.         self.canvas.configure(yscrollcommand=scrollbar.set)
  62.         self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
  63.         scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
  64.         # ================= 第五部分:执行按钮 =================
  65.         bottom_frame = tk.Frame(self.root)
  66.         bottom_frame.pack(fill=tk.X, pady=15)
  67.         tk.Button(bottom_frame, text="&#9889; 3. 确认无误,执行真实修改", command=self.execute_rename, bg="#ffecb3", font=("微软雅黑", 11, "bold"), width=30).pack()
  68.     # ---------------- 核心逻辑区 ----------------
  69.     def select_files(self):
  70.         """打开文件选择器,并将选中的文件 追加 到滚动列表中"""
  71.         paths = filedialog.askopenfilenames(title="请按住 Ctrl 多选你要修改的文件 (可多次追加)")
  72.         if not paths:
  73.             return
  74.         # 提取当前已经在列表里的旧路径,防止重复添加
  75.         existing_paths = [item['old_path'] for item in self.file_items]
  76.         added_count = 0
  77.         # 渲染新选中的文件
  78.         for path in paths:
  79.             # 去重:如果文件已经在列表里,跳过
  80.             if path in existing_paths:
  81.                 continue
  82.                  
  83.             dir_name, file_name = os.path.split(path)
  84.             
  85.             row_frame = tk.Frame(self.scrollable_frame)
  86.             row_frame.pack(fill=tk.X, pady=3, padx=5)
  87.             # 左侧文字
  88.             tk.Label(row_frame, text=file_name, width=40, anchor='w', fg="#333333").pack(side=tk.LEFT)
  89.             # 右侧输入框
  90.             new_name_var = tk.StringVar(value=file_name)
  91.             entry = tk.Entry(row_frame, textvariable=new_name_var, width=45)
  92.             entry.pack(side=tk.LEFT, padx=10)
  93.             # 准备数据结构
  94.             item_data = {
  95.                 'old_path': path,
  96.                 'new_name_var': new_name_var,
  97.                 'row_frame': row_frame
  98.             }
  99.             # 新增:剔除本行按钮
  100.             btn_remove = tk.Button(row_frame, text="&#10060;", fg="red", relief=tk.FLAT,
  101.                                    command=lambda d=item_data: self.remove_item(d))
  102.             btn_remove.pack(side=tk.LEFT, padx=5)
  103.             # 加入全局列表
  104.             self.file_items.append(item_data)
  105.             added_count += 1
  106.         self.update_status_label()
  107.     def remove_item(self, item_data):
  108.         """从列表中剔除单个文件"""
  109.         # 销毁UI组件
  110.         item_data['row_frame'].destroy()
  111.         # 从数据列表中移除
  112.         self.file_items.remove(item_data)
  113.         self.update_status_label()
  114.     def clear_list(self):
  115.         """一键清空所有已选文件"""
  116.         if not self.file_items:
  117.             return
  118.         if messagebox.askyesno("确认", "确定要清空当前所有已选择的文件吗?"):
  119.             for item in self.file_items:
  120.                 item['row_frame'].destroy()
  121.             self.file_items.clear()
  122.             self.update_status_label()
  123.     def update_status_label(self):
  124.         """更新文件数量显示"""
  125.         count = len(self.file_items)
  126.         if count == 0:
  127.             self.status_label.config(text="当前未选择任何文件")
  128.         else:
  129.             self.status_label.config(text=f"已加载 {count} 个文件")
  130.     def apply_batch_replace(self):
  131.         """将上方设置的替换规则,应用到右侧所有的输入框中(预览效果)"""
  132.         old_str = self.old_str_var.get()
  133.         new_str = self.new_str_var.get()
  134.         if not old_str:
  135.             messagebox.showinfo("提示", "请输入需要被替换的字符!")
  136.             return
  137.          
  138.         for item in self.file_items:
  139.             current_new_name = item['new_name_var'].get()
  140.             updated_name = current_new_name.replace(old_str, new_str)
  141.             item['new_name_var'].set(updated_name)
  142.     def apply_batch_extension(self):
  143.         """将上方设置的新后缀,应用到右侧所有的输入框中(预览效果)"""
  144.         new_ext = self.new_ext_var.get().strip()
  145.         if not new_ext:
  146.             messagebox.showinfo("提示", "请输入新的后缀名,例如 .png 或 .txt")
  147.             return
  148.             
  149.         if not new_ext.startswith("."):
  150.             new_ext = "." + new_ext
  151.         for item in self.file_items:
  152.             current_new_name = item['new_name_var'].get()
  153.             base_name, _ = os.path.splitext(current_new_name)
  154.             item['new_name_var'].set(base_name + new_ext)
  155.     def execute_rename(self):
  156.         """遍历列表,将名称发生改变的文件进行真实的系统重命名"""
  157.         if not self.file_items:
  158.             messagebox.showwarning("提示", "列表为空,请先选择文件!")
  159.             return
  160.         success_count = 0
  161.         error_messages = []
  162.         for item in self.file_items:
  163.             old_path = item['old_path']
  164.             new_file_name = item['new_name_var'].get().strip()
  165.             dir_name, old_file_name = os.path.split(old_path)
  166.             if new_file_name == old_file_name or not new_file_name:
  167.                 continue
  168.             new_path = os.path.join(dir_name, new_file_name)
  169.             try:
  170.                 if os.path.exists(new_path) and new_path.lower() != old_path.lower():
  171.                     error_messages.append(f"跳过: '{new_file_name}' 已存在。")
  172.                     continue
  173.                  
  174.                 os.rename(old_path, new_path)
  175.                  
  176.                 item['old_path'] = new_path
  177.                 success_count += 1
  178.                  
  179.             except Exception as e:
  180.                 error_messages.append(f"失败: '{old_file_name}' -> {str(e)}")
  181.         # 为了避免重新选文件,修改成功后刷新列表展示的新老名字一致
  182.         for item in self.file_items:
  183.             _, current_name = os.path.split(item['old_path'])
  184.             item['new_name_var'].set(current_name)
  185.             # 更新左侧UI显示的标签
  186.             for child in item['row_frame'].winfo_children():
  187.                 if isinstance(child, tk.Label):
  188.                     child.config(text=current_name)
  189.                     break
  190.         if error_messages:
  191.             error_text = "\n".join(error_messages[:5])
  192.             if len(error_messages) > 5:
  193.                 error_text += "\n..."
  194.             messagebox.showwarning("部分完成", f"成功修改 {success_count} 个文件。\n\n以下出现问题:\n{error_text}")
  195.         elif success_count > 0:
  196.             messagebox.showinfo("完成", f"&#127881; 成功修改 {success_count} 个文件!")
  197.         else:
  198.             messagebox.showinfo("提示", "没有检测到任何名称的更改。")
  199. if __name__ == "__main__":
  200.     root = tk.Tk()
  201.     app = UltimateRenameTool(root)
  202.     root.mainloop()
复制代码

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

下载地址

https://www.alipan.com/s/mPtY72SMuHo

© 版权声明

相关文章