链接:https://pan.baidu.com/s/11FP1Q4HEmk3XU78nGIRs2Q?pwd=8j87

import os
import tkinter as tk
from tkinter import filedialog, messagebox
classBatchRenameApp:
def__init__(self, root):
self.root = root
self.root.geometry("850x550")
self.current_dir =""
self.old_filenames = [] # 原始文件名列表
self.entry_widgets = [] # 新文件名输入框列表
self.create_widgets()
defcreate_widgets(self):
# 顶部:选择文件夹
top_frame = tk.Frame(self.root)
top_frame.pack(pady=10, fill=tk.X, padx=10)
tk.Button(top_frame, text="选择文件夹", command=self.select_folder).pack(side=tk.LEFT, padx=5)
self.path_label = tk.Label(top_frame, text="未选择文件夹", anchor="w", relief=tk.SUNKEN)
self.path_label.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
# 提示标签
info_label = tk.Label(self.root, text="💡 提示:在右侧任意输入框中按 Ctrl+V 可批量粘贴多行新文件名;点击下方按钮可复制所有新文件名",
fg="blue", anchor="w")
info_label.pack(pady=(0,5), padx=10, fill=tk.X)
# 标题行
title_frame = tk.Frame(self.root)
title_frame.pack(pady=5, fill=tk.X, padx=10)
tk.Label(title_frame, text="原文件名", width=35, anchor="center", font=("Arial", 10, "bold")).pack(side=tk.LEFT, padx=5)
tk.Label(title_frame, text="新文件名(需包含后缀)", width=45, anchor="center", font=("Arial", 10, "bold")).pack(side=tk.LEFT, padx=5)
# 滚动区域(Canvas + Scrollbar)
canvas = tk.Canvas(self.root)
scrollbar = tk.Scrollbar(self.root, orient="vertical", command=canvas.yview)
self.scrollable_frame = tk.Frame(canvas)
self.scrollable_frame.bind("<Configure>", lambdae: canvas.configure(scrollregion=canvas.bbox("all")))
canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
canvas.configure(yscrollcommand=scrollbar.set)
canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(10,0), pady=10)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y, pady=10)
# 底部按钮区域:垂直排列
bottom_frame = tk.Frame(self.root)
bottom_frame.pack(pady=10, fill=tk.X)
self.rename_btn = tk.Button(bottom_frame, text="开始重命名", command=self.rename_files, state=tk.DISABLED)
self.rename_btn.pack(side=tk.TOP, pady=2)
self.copy_btn = tk.Button(bottom_frame, text="复制所有新文件名", command=self.copy_all_new_names, state=tk.DISABLED)
self.copy_btn.pack(side=tk.TOP, pady=2)
self.status_label = tk.Label(bottom_frame, text="就绪", fg="blue")
self.status_label.pack(side=tk.TOP, pady=2)
defselect_folder(self):
folder = filedialog.askdirectory()
if folder:
self.current_dir = folder
self.path_label.config(text=self.current_dir)
self.load_files()
defload_files(self):
# 清空旧数据
for widget inself.scrollable_frame.winfo_children():
widget.destroy()
self.old_filenames.clear()
self.entry_widgets.clear()
ifnot os.path.isdir(self.current_dir):
self.copy_btn.config(state=tk.DISABLED)
return
try:
all_items = os.listdir(self.current_dir)
files = [f for f in all_items if os.path.isfile(os.path.join(self.current_dir, f))]
exceptExceptionas e:
messagebox.showerror("错误", f"无法读取文件夹:{e}")
self.copy_btn.config(state=tk.DISABLED)
return
ifnot files:
self.status_label.config(text="文件夹中没有文件", fg="orange")
self.rename_btn.config(state=tk.DISABLED)
self.copy_btn.config(state=tk.DISABLED)
return
self.status_label.config(text=f"已加载 {len(files)} 个文件,可批量粘贴/复制", fg="green")
self.rename_btn.config(state=tk.NORMAL)
self.copy_btn.config(state=tk.NORMAL)
for i, fname inenumerate(files):
self.old_filenames.append(fname)
# 原文件名标签
lbl = tk.Label(self.scrollable_frame, text=fname, width=35, anchor="w", relief=tk.RIDGE)
lbl.grid(row=i, column=0, padx=5, pady=2, sticky="ew")
# 新文件名输入框,默认填入原文件名
entry = tk.Entry(self.scrollable_frame, width=45)
entry.insert(0, fname)
entry.grid(row=i, column=1, padx=5, pady=2, sticky="ew")
# 绑定 Ctrl+V 实现批量粘贴
entry.bind("<Control-v>", self.paste_multiline)
self.entry_widgets.append(entry)
self.scrollable_frame.columnconfigure(0, weight=1)
self.scrollable_frame.columnconfigure(1, weight=2)
defpaste_multiline(self, event):
"""在输入框中按 Ctrl+V 时触发:支持多行文本批量填充"""
current_entry = event.widget
try:
clip_text =self.root.clipboard_get()
except:
return
lines = clip_text.splitlines()
lines = [line.strip() for line in lines if line.strip()]
ifnot lines:
return
try:
start_index =self.entry_widgets.index(current_entry)
exceptValueError:
return
for i, new_name inenumerate(lines):
target_index = start_index + i
if target_index >=len(self.entry_widgets):
break
self.entry_widgets[target_index].delete(0, tk.END)
self.entry_widgets[target_index].insert(0, new_name)
next_index = start_index +len(lines)
if next_index <len(self.entry_widgets):
self.entry_widgets[next_index].focus_set()
return"break"
defcopy_all_new_names(self):
"""复制所有新文件名(每行一个)到剪贴板"""
ifnotself.entry_widgets:
messagebox.showinfo("提示", "没有可复制的内容")
return
new_names = [entry.get() for entry inself.entry_widgets]
text_to_copy ="\n".join(new_names)
self.root.clipboard_clear()
self.root.clipboard_append(text_to_copy)
self.status_label.config(text=f"已复制 {len(new_names)} 个文件名到剪贴板", fg="green")
# 可选:短暂提示恢复
self.root.after(2000, lambda: self.status_label.config(text="就绪", fg="blue"))
defrename_files(self):
ifnotself.current_dir:
messagebox.showwarning("警告", "请先选择一个文件夹")
return
# 收集新文件名并校验
new_names = []
for entry inself.entry_widgets:
new_name = entry.get().strip()
ifnot new_name:
messagebox.showerror("错误", "新文件名不能为空,请填写所有新文件名")
return
if'/'in new_name or'\\'in new_name:
messagebox.showerror("错误", f"文件名不能包含路径分隔符:{new_name}")
return
new_names.append(new_name)
iflen(set(new_names)) !=len(new_names):
messagebox.showerror("错误", "存在重复的新文件名,请确保每个新文件名唯一")
return
all_files =set(os.listdir(self.current_dir))
conflicts = []
for old, new inzip(self.old_filenames, new_names):
if new != old and new in all_files:
conflicts.append(new)
if conflicts:
messagebox.showerror("错误", f"以下新文件名已存在,请修改:\n"+"\n".join(conflicts))
return
renamed_count =0
errors = []
for old, new inzip(self.old_filenames, new_names):
if old == new:
continue
old_path = os.path.join(self.current_dir, old)
new_path = os.path.join(self.current_dir, new)
try:
os.rename(old_path, new_path)
renamed_count +=1
exceptExceptionas e:
errors.append(f"{old} → {new} : {str(e)}")
if errors:
messagebox.showerror("部分失败", "\n".join(errors))
else:
messagebox.showinfo("完成", f"成功重命名 {renamed_count} 个文件")
self.load_files()
self.status_label.config(text="重命名完成", fg="blue")
if__name__=="__main__":
root = tk.Tk()
app = BatchRenameApp(root)
root.mainloop()
夜雨聆风