我的工作场景会遇到许多文件夹下有许多文件,文件名不太规则而且还很长,我需要抓取这些文件名中的关键字来匹配其他的数据,然后在将这些文件改成规则的文件名,所以做了这个小工具分享给大家。
文件名抓改工具:
https://wwzk.lanzouo.com/iF0TA2r0dpxg
密码:i522
文件名修改后可以通过下面这个工具来验证,之前发布在另外的帖子里了。
https://bbs.songma.com/thread-2014155-1-1.html


import os
import pandas as pd
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
from tkinter import messagebox
import re
import shutil
from datetime import datetime
from tkinter import scrolledtext
from PIL import Image, ImageTk
import io
import sys
class FileManagementApp:
def __init__(self, root):
self.root = root
self.root.title("文件名抓改系统V2.1 By来乐老弟")
self.root.geometry("1024x768")
self.root.minsize(800, 600)
# 配置主窗口的网格布局
self.root.grid_rowconfigure(0, weight=1)
self.root.grid_columnconfigure(0, weight=1)
# 设置主题样式
style = ttk.Style()
style.configure("TNotebook", background="#f0f0f0")
style.configure("TFrame", background="#ffffff")
style.configure("TButton", padding=5)
style.configure("Reward.TButton", font=("SimHei", 9, "bold"), foreground="blue")
# 初始化选择的文件夹列表
self.selected_folders = []
# 绑定快捷键
self.root.bind("<Control-o>", lambda e: self.select_folder())
self.root.bind("<Control-e>", lambda e: self.export_files())
self.root.bind("<Control-r>", lambda e: self.rename_files())
self.root.bind("<Control-z>", lambda e: self.undo_renaming())
# 绑定快捷键
self.root.bind("<Control-o>", lambda e: self.select_folder())
self.root.bind("<Control-e>", lambda e: self.export_files())
self.root.bind("<Control-r>", lambda e: self.rename_files())
self.root.bind("<Control-z>", lambda e: self.undo_renaming())
# 初始化文件信息列表
self.all_files_info = []
# 初始化备份信息
self.backup_info = []
# 绑定窗口关闭事件
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
# 创建主选项卡
self.notebook = ttk.Notebook(root)
self.notebook.grid(row=0, column=0, sticky="nsew", padx=5, pady=5)
# 创建文件名抓取页面
self.create_file_capture_tab()
# 创建文件名修改页面
self.create_file_rename_tab()
def create_file_capture_tab(self):
# 文件名抓取页面
self.capture_tab = ttk.Frame(self.notebook)
self.notebook.add(self.capture_tab, text='文件名抓取')
# 创建顶部框架
top_frame = ttk.Frame(self.capture_tab)
top_frame.pack(fill='x', padx=10, pady=5)
# 文件夹选择
self.folder_label = ttk.Label(top_frame, text="选择文件夹(Ctrl+O):")
self.folder_label.pack(side='left', padx=5)
self.folder_entry = ttk.Entry(top_frame, width=50)
self.folder_entry.pack(side='left', padx=5)
self.browse_button = ttk.Button(top_frame, text="浏览...", command=self.select_folder)
self.browse_button.pack(side='left', padx=5)
self.append_button = ttk.Button(top_frame, text="追加文件夹", command=self.append_folder)
self.append_button.pack(side='left', padx=5)
# 创建主框架
main_frame = ttk.Frame(self.capture_tab)
main_frame.pack(fill='both', expand=True, padx=10, pady=5)
# 子目录选项
options_frame = ttk.Frame(main_frame)
options_frame.pack(fill='x', pady=5)
self.subdir_var = tk.BooleanVar(value=True)
self.subdir_check = ttk.Checkbutton(options_frame, text="读取子目录文件", variable=self.subdir_var)
self.subdir_check.pack(side='left')
# 文件列表显示(带滚动条)
list_frame = ttk.Frame(main_frame)
list_frame.pack(fill='both', expand=True)
self.listbox = tk.Listbox(list_frame, selectmode='extended')
scrollbar_y = ttk.Scrollbar(list_frame, orient='vertical', command=self.listbox.yview)
scrollbar_x = ttk.Scrollbar(list_frame, orient='horizontal', command=self.listbox.xview)
self.listbox.configure(yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set)
scrollbar_y.pack(side='right', fill='y')
scrollbar_x.pack(side='bottom', fill='x')
self.listbox.pack(side='left', fill='both', expand=True)
# 底部工具栏
bottom_frame = ttk.Frame(self.capture_tab)
bottom_frame.pack(fill='x', padx=10, pady=5)
self.export_button = ttk.Button(bottom_frame, text="导出到Excel(Ctrl+E)", command=self.export_files)
self.export_button.pack(side='left', padx=5)
# 添加赏赞按钮
self.reward_button = ttk.Button(bottom_frame, text="赏赞", command=self.show_reward, style="Reward.TButton")
self.reward_button.pack(side='left', padx=5)
# 进度条
self.progress_var = tk.DoubleVar()
self.progress_bar = ttk.Progressbar(bottom_frame, length=300, mode='determinate', variable=self.progress_var)
self.progress_bar.pack(side='left', padx=10, fill='x', expand=True)
# 手动分割区域
split_frame = ttk.Frame(self.capture_tab)
split_frame.pack(fill='x', padx=10, pady=5)
split_label = ttk.Label(split_frame, text="手动分割设置:")
split_label.pack(side='left', padx=5)
# 添加说明文字
help_text = "说明:通过添加分割字段来设置文件名的分割规则。在示例值中填入与实际文件名对应位置一样长度的字符,系统将按照示例值的长度依次分割文件名。"
help_label = ttk.Label(split_frame, text=help_text, wraplength=600)
help_label.pack(side='top', padx=5, pady=5)
self.split_entries = []
self.split_frame = split_frame
add_split_button = ttk.Button(split_frame, text="添加分割字段", command=self.add_split_entry)
add_split_button.pack(side='left', padx=5)
# 状态显示
self.status_label = ttk.Label(bottom_frame, text="")
style = ttk.Style()
style.configure('Status.TLabel', foreground='blue')
self.status_label.configure(style='Status.TLabel')
self.status_label.pack(side='right', padx=5)
# 绑定列表选择事件
self.listbox.bind('<<ListboxSelect>>', self.on_select_file)
def create_file_rename_tab(self):
# 文件名修改页面
self.rename_tab = ttk.Frame(self.notebook)
self.notebook.add(self.rename_tab, text='文件名修改')
# 创建顶部框架
top_frame = ttk.Frame(self.rename_tab)
top_frame.pack(fill='x', padx=10, pady=5)
# Excel文件选择
self.excel_label = ttk.Label(top_frame, text="选择Excel文件(Ctrl+E):")
self.excel_label.pack(side='left', padx=5)
self.excel_entry = ttk.Entry(top_frame, width=50)
self.excel_entry.pack(side='left', padx=5)
self.excel_button = ttk.Button(top_frame, text="浏览...", command=self.select_excel_file)
self.excel_button.pack(side='left', padx=5)
# 创建主框架
main_frame = ttk.Frame(self.rename_tab)
main_frame.pack(fill='both', expand=True, padx=10, pady=5)
# 预览表格
self.tree = ttk.Treeview(main_frame, columns=('A', 'B'), show='headings')
self.tree.pack(pady=10, fill='both', expand=True)
# 列选择
self.column_frame = ttk.Frame(main_frame)
self.column_frame.pack(fill='x', pady=5)
self.old_name_label = ttk.Label(self.column_frame, text="原文件名列:")
self.old_name_label.pack(side=tk.LEFT, padx=5)
self.old_name_combobox = ttk.Combobox(self.column_frame, state='readonly')
self.old_name_combobox.pack(side=tk.LEFT, padx=5)
self.new_name_label = ttk.Label(self.column_frame, text="新文件名列:")
self.new_name_label.pack(side=tk.LEFT, padx=5)
self.new_name_combobox = ttk.Combobox(self.column_frame, state='readonly')
self.new_name_combobox.pack(side=tk.LEFT, padx=5)
# 操作按钮
bottom_frame = ttk.Frame(self.rename_tab)
bottom_frame.pack(fill='x', padx=10, pady=5)
self.rename_button = ttk.Button(bottom_frame, text="执行重命名(Ctrl+R)", command=self.rename_files)
self.rename_button.pack(side='left', padx=5)
self.undo_button = ttk.Button(bottom_frame, text="撤回修改(Ctrl+Z)", command=self.undo_renaming)
self.undo_button.pack(side='left', padx=5)
self.cleanup_button = ttk.Button(bottom_frame, text="清理备份", command=self.cleanup_backups)
self.cleanup_button.pack(side='left', padx=5)
# 添加赏赞按钮
self.reward_button_rename = ttk.Button(bottom_frame, text="赏赞", command=self.show_reward, style="Reward.TButton")
self.reward_button_rename.pack(side='left', padx=5)
# 进度条
self.rename_progress_var = tk.DoubleVar()
self.rename_progress_bar = ttk.Progressbar(bottom_frame, length=300, mode='determinate', variable=self.rename_progress_var)
self.rename_progress_bar.pack(side='left', padx=10, fill='x', expand=True)
# 状态显示
self.rename_status_label = ttk.Label(bottom_frame, text="")
style = ttk.Style()
style.configure('RenameStatus.TLabel', foreground='blue')
self.rename_status_label.configure(style='RenameStatus.TLabel')
self.rename_status_label.pack(side='right', padx=5)
def select_folder(self):
folder = filedialog.askdirectory()
if folder:
self.selected_folders = [folder]
self.folder_entry.delete(0, tk.END)
self.folder_entry.insert(0, folder)
self.collect_files(self.selected_folders)
def append_folder(self):
folder = filedialog.askdirectory()
if folder:
if folder not in self.selected_folders:
self.selected_folders.append(folder)
current_text = self.folder_entry.get()
if current_text:
self.folder_entry.delete(0, tk.END)
self.folder_entry.insert(0, current_text + "; " + folder)
else:
self.folder_entry.insert(0, folder)
self.collect_files(self.selected_folders)
def collect_files(self, folders):
self.listbox.delete(0, tk.END)
self.all_files_info = []
if isinstance(folders, str):
folders = [folders]
total_files = 0
for folder in folders:
total_files += sum([len(files) for _, _, files in os.walk(folder)])
processed_files = 0
for folder in folders:
for root, dirs, files in os.walk(folder):
if not self.subdir_var.get() and root != folder:
continue
for file in files:
file_path = os.path.join(root, file)
file_info = self.analyze_filename(file_path)
self.all_files_info.append(file_info)
self.listbox.insert(tk.END, file_info['file_name'])
processed_files += 1
progress = (processed_files / total_files) * 100
self.progress_var.set(progress)
self.status_label.config(text=f"正在处理: {processed_files}/{total_files}")
self.root.update()
if not self.all_files_info:
self.status_label.config(text="没有找到任何文件!", foreground="red")
else:
self.status_label.config(text=f"共找到 {len(self.all_files_info)} 个文件", foreground="green")
self.progress_var.set(0)
def analyze_filename(self, file_path):
"""文件名智能分析逻辑,提取文件名中的各种信息"""
file_stats = os.stat(file_path)
# 获取文件名和扩展名
file_name = os.path.basename(file_path)
# 获取文件所在文件夹名
folder_name = os.path.dirname(file_path)
# 获取文件大小(KB)
size_kb = file_stats.st_size / 1024
# 获取文件创建时间
create_time = datetime.fromtimestamp(file_stats.st_ctime).strftime('%Y-%m-%d %H:%M:%S')
# 获取文件修改时间
modify_time = datetime.fromtimestamp(file_stats.st_mtime).strftime('%Y-%m-%d %H:%M:%S')
# 获取文件扩展名
_, extension = os.path.splitext(file_path)
# 自动提取文件名中的各种信息
try:
# 动态提取所有数字部分
numbers = re.findall(r'd+', file_name)
number = numbers[0] if numbers else ''
# 动态提取所有中文字符
chinese_chars = re.findall(r'[u4e00-u9fa5]+', file_name)
name = chinese_chars[0] if chinese_chars else ''
# 动态提取电话号码(支持多种格式)
phone_patterns = [
r'1d{10}',
r'd{3} d{4} d{4}',
r'd{3}-d{4}-d{4}',
r'd{3}.d{4}.d{4}'
]
phone = ''
for pattern in phone_patterns:
match = re.search(pattern, file_name)
if match:
phone = match.group(0)
break
# 动态提取特殊符号
special_chars = re.findall(r'[^wsu4e00-u9fa5]', file_name)
special_chars = ''.join(set(special_chars))
# 动态提取英文单词
english_words = re.findall(r'[A-Za-z]+', file_name)
# 动态提取日期时间(支持更多格式)
datetime_patterns = [
r'd{4}-d{2}-d{2}',
r'd{4}d{2}d{2}',
r'd{2}-d{2}-d{4}',
r'd{2}d{2}d{4}',
r'd{4}年d{2}月d{2}日',
r'd{2}月d{2}日d{4}'
]
dates = []
for pattern in datetime_patterns:
dates.extend(re.findall(pattern, file_name))
# 动态提取时间格式
time_patterns = [
r'd{2}:d{2}:d{2}',
r'd{2}-d{2}-d{2}',
r'd{2}d{2}d{2}',
r'd{2}时d{2}分d{2}秒'
]
times = []
for pattern in time_patterns:
times.extend(re.findall(pattern, file_name))
except Exception as e:
number = ''
name = ''
phone = ''
special_chars = ''
english_words = []
dates = []
times = []
return {
'folder': folder_name,
'file_name': file_name,
'number': number,
'name': name,
'phone': phone,
'extension': extension,
'size_kb': round(size_kb, 2),
'create_time': create_time,
'modify_time': modify_time,
'full_path': file_path,
'special_chars': special_chars,
'english_words': ','.join(english_words),
'dates': ','.join(dates),
'times': ','.join(times)
}
def select_excel_file(self):
file_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx")])
if file_path:
self.excel_entry.delete(0, tk.END)
self.excel_entry.insert(0, file_path)
self.preview_excel(file_path)
def preview_excel(self, file_path):
try:
self.df = pd.read_excel(file_path)
self.update_column_comboboxes()
self.update_treeview()
except Exception as e:
messagebox.showerror("错误", f"无法打开Excel文件: {str(e)}")
def update_column_comboboxes(self):
columns = self.df.columns.tolist()
self.old_name_combobox['values'] = columns
self.new_name_combobox['values'] = columns
def update_treeview(self):
# 清空Treeview
for i in self.tree.get_children():
self.tree.delete(i)
# 设置列标题
columns = self.df.columns.tolist()
self.tree['columns'] = columns
for col in columns:
self.tree.heading(col, text=col)
self.tree.column(col, width=100, anchor='w')
# 添加数据
for _, row in self.df.iterrows():
self.tree.insert('', 'end', values=row.tolist())
def on_select_file(self, event):
"""处理文件选择事件"""
pass
def rename_files(self):
"""重命名文件的主要方法"""
# 验证Excel文件和列选择
if not hasattr(self, 'df') or self.df.empty:
messagebox.showerror("错误", "请先选择并预览Excel文件!")
return
if not self.old_name_combobox.get() or not self.new_name_combobox.get():
messagebox.showerror("错误", "请选择原文件名列和新文件名列!")
return
try:
# 获取列名
old_col = self.old_name_combobox.get()
new_col = self.new_name_combobox.get()
rename_count = 0
failed_files = []
self.backup_info = [] # 清空之前的备份信息
# 处理每一行数据
for _, row in self.df.iterrows():
old_name = str(row[old_col])
new_name = str(row[new_col])
if not old_name or not new_name:
continue
# 统一路径格式
file_path = old_name.replace('\', '/')
# 验证文件路径
if not file_path or not os.path.exists(file_path):
# 尝试通过文件名匹配获取完整路径
if hasattr(self, 'all_files_info') and self.all_files_info:
print(f'尝试匹配文件名: {old_name}')
file_path = self.find_file_by_name(old_name)
# 最终验证路径
if not file_path or not os.path.exists(file_path):
failed_files.append(f"未找到文件路径: {file_path}")
continue
# 组合新路径
new_path = os.path.join(os.path.dirname(file_path), new_name).replace('\', '/')
# 验证目标路径
if os.path.exists(new_path):
failed_files.append(f"目标文件已存在: {new_path}")
continue
# 验证权限
if not os.access(file_path, os.W_OK):
failed_files.append(f"没有写权限: {file_path}")
continue
try:
# 创建备份
backup_path = self.backup_file(file_path)
if backup_path:
self.backup_info.append((backup_path, file_path, new_path))
# 执行重命名
os.rename(file_path, new_path)
rename_count += 1
print(f'成功重命名: {file_path} -> {new_path}')
except PermissionError:
failed_files.append(f"权限错误: {file_path}")
print(f'权限错误: {file_path}')
except Exception as e:
failed_files.append(f"{old_name} -> {new_name}: {str(e)}")
print(f'重命名错误: {str(e)}')
# 显示结果
result_message = f"成功重命名 {rename_count} 个文件
失败 {len(failed_files)} 个文件"
if failed_files:
result_message += "
失败缘由:
" + "
".join(failed_files)
style = ttk.Style()
style.configure('RenameSuccess.TLabel', foreground='green')
self.rename_status_label.configure(style='RenameSuccess.TLabel')
self.rename_status_label.configure(text=result_message)
messagebox.showinfo("完成", result_message)
except Exception as e:
messagebox.showerror("错误", f"重命名过程中发生错误: {str(e)}")
# 保存日志
if failed_files:
self.save_log(failed_files)
def find_file_by_name(self, name):
"""通过文件名查找文件路径"""
for file_info in self.all_files_info:
# 清理名称,忽略大小写、空格和特殊字符
clean_name = re.sub(r'[^wu4e00-u9fa5]', '', name)
clean_file_name = re.sub(r'[^wu4e00-u9fa5]', '', file_info['file_name'])
# 尝试多种匹配方式
if (clean_name.lower() in clean_file_name.lower() or
re.search(r'' + re.escape(clean_name) + r'', file_info['file_name'], re.IGNORECASE)):
return file_info['full_path']
return None
def backup_file(self, file_path):
"""创建文件备份"""
try:
backup_dir = os.path.join(os.path.dirname(file_path), '.backup')
os.makedirs(backup_dir, exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
filename = os.path.basename(file_path)
backup_path = os.path.join(backup_dir, f"{timestamp}_{filename}")
shutil.copy2(file_path, backup_path)
return backup_path
except Exception as e:
print(f"备份文件失败: {str(e)}")
return None
def add_split_entry(self):
"""添加一个新的分割字段输入框"""
if len(self.split_entries) >= 10: # 限制最大输入框数量
messagebox.showinfo("提示", "最多只能添加10个分割字段!")
return
entry_frame = ttk.Frame(self.split_frame)
entry_frame.pack(fill='x', pady=2)
# 添加列标签
col_label = ttk.Label(entry_frame, text=f"第{len(self.split_entries) + 1}列:")
col_label.pack(side='left', padx=2)
# 添加示例值输入框
split_label = ttk.Label(entry_frame, text="示例值:")
split_label.pack(side='left', padx=2)
split_entry = ttk.Entry(entry_frame, width=20)
split_entry.pack(side='left', padx=2)
# 隐藏的name_entry用于保持代码兼容性
name_entry = ttk.Entry(entry_frame)
name_entry.pack_forget()
def remove_entry():
entry_frame.destroy()
self.split_entries.remove((name_entry, split_entry, entry_frame))
remove_button = ttk.Button(entry_frame, text="删除", command=remove_entry)
remove_button.pack(side='left', padx=2)
self.split_entries.append((name_entry, split_entry, entry_frame))
def export_files(self):
"""将收集的文件信息导出到Excel"""
if not self.all_files_info:
messagebox.showinfo("提示", "没有文件可以导出!")
return
try:
# 创建导出文件名
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
export_filename = f"文件列表_{timestamp}.xlsx"
export_path = filedialog.asksaveasfilename(
defaultextension=".xlsx",
filetypes=[("Excel files", "*.xlsx")],
initialfile=export_filename
)
if not export_path:
return # 用户撤销了保存对话框
# 创建DataFrame并导出
df = pd.DataFrame(self.all_files_info)
# 合并并转换文件路径格式
df['full_path'] = df.apply(lambda row: os.path.join(row['folder'], row['full_path']).replace('\', '/'), axis=1)
df = df.drop('folder', axis=1) # 删除单独的folder列
# 添加手动分割的列
if self.split_entries:
# 为每个文件名创建分割结果
for idx, (name_entry, split_entry, _) in enumerate(self.split_entries):
split_value = split_entry.get().strip()
if not split_value:
continue
field_name = f'分割_{idx + 1}' # 使用更有意义的列名
split_length = len(split_value) # 获取示例值的长度
# 根据示例值的长度来分割文件名
def split_filename(filename):
# 如果文件名为空,返回空字符串
if not filename:
return ''
try:
# 获取当前处理的文件名位置
start_pos = 0
for i in range(idx):
prev_split_value = self.split_entries[i][1].get().strip()
if prev_split_value:
start_pos += len(prev_split_value)
# 根据示例值的长度提取对应位数的字符
if start_pos < len(filename):
return filename[start_pos:start_pos + split_length]
except Exception:
pass
# 如果提取失败,返回空字符串
return ''
df[field_name] = df['file_name'].apply(split_filename)
# 重新排列列的顺序
columns_order = ['file_name'] # 第一添加原始文件名
# 添加分割列(只添加实际存在的分割列)
split_columns = [f'分割_{i + 1}' for i in range(len(self.split_entries))
if self.split_entries[i][1].get().strip()]
columns_order.extend(split_columns)
# 添加其他重大信息
other_columns = ['full_path', 'size_kb', 'create_time', 'modify_time']
columns_order.extend([col for col in other_columns if col in df.columns])
# 仅保留存在的列
existing_columns = [col for col in columns_order if col in df.columns]
df = df[existing_columns]
# 导出到Excel
df.to_excel(export_path, index=False)
style = ttk.Style()
style.configure('Success.TLabel', foreground='green')
self.status_label.configure(style='Success.TLabel')
self.status_label.configure(text=f"已成功导出 {len(self.all_files_info)} 个文件信息到 {export_path}")
messagebox.showinfo("成功", f"文件信息已成功导出到:
{export_path}")
except Exception as e:
style = ttk.Style()
style.configure('Error.TLabel', foreground='red')
self.status_label.configure(style='Error.TLabel')
self.status_label.configure(text=f"导出失败: {str(e)}")
messagebox.showerror("错误", f"导出文件时发生错误:
{str(e)}")
def undo_renaming(self):
"""撤销之前的重命名操作"""
if not self.backup_info:
messagebox.showinfo("提示", "没有可以撤销的重命名操作!")
return
try:
undo_count = 0
failed_undo = []
# 反向遍历备份信息,以便按照相反的顺序撤销操作
for backup_path, original_path, new_path in reversed(self.backup_info):
try:
# 检查当前文件是否存在
if os.path.exists(new_path):
# 检查备份文件是否存在
if os.path.exists(backup_path):
# 先删除当前文件,然后恢复备份
os.remove(new_path)
shutil.copy2(backup_path, original_path)
undo_count += 1
else:
# 如果备份不存在,尝试直接重命名回去
os.rename(new_path, original_path)
undo_count += 1
else:
# 如果新文件不存在,但备份存在,直接恢复备份
if os.path.exists(backup_path):
shutil.copy2(backup_path, original_path)
undo_count += 1
else:
failed_undo.append(f"无法撤销: {new_path} -> {original_path} (备份文件不存在)")
except Exception as e:
failed_undo.append(f"撤销失败: {new_path} -> {original_path}: {str(e)}")
# 清空备份信息
self.backup_info = []
# 显示结果
result_message = f"成功撤销 {undo_count} 个重命名操作"
if failed_undo:
result_message += f"
失败 {len(failed_undo)} 个操作"
result_message += "
失败缘由:
" + "
".join(failed_undo)
style = ttk.Style()
style.configure('RenameSuccess.TLabel', foreground='green')
self.rename_status_label.configure(style='RenameSuccess.TLabel')
self.rename_status_label.configure(text=result_message)
messagebox.showinfo("完成", result_message)
except Exception as e:
messagebox.showerror("错误", f"撤销重命名时发生错误: {str(e)}")
def save_log(self, failed_items, prefix="重命名"):
"""保存操作日志"""
try:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
log_filename = f"{prefix}日志_{timestamp}.txt"
with open(log_filename, 'w', encoding='utf-8') as f:
f.write(f"{prefix}操作日志 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
")
f.write("=" * 50 + "
")
for item in failed_items:
f.write(f"{item}
")
print(f"日志已保存到: {log_filename}")
return log_filename
except Exception as e:
print(f"保存日志失败: {str(e)}")
return None
def cleanup_backups(self):
"""清理所有备份文件"""
try:
cleaned_count = 0
failed_paths = []
processed_dirs = set()
# 从已知的备份信息中获取目录
for backup_path, _, _ in self.backup_info:
backup_dir = os.path.dirname(backup_path)
processed_dirs.add(os.path.dirname(backup_dir))
# 从当前文件列表中获取目录
if hasattr(self, 'all_files_info'):
for file_info in self.all_files_info:
dir_path = os.path.dirname(file_info.get('file_path', ''))
if dir_path:
processed_dirs.add(dir_path)
# 清理每个目录中的备份文件
for dir_path in processed_dirs:
backup_dir = os.path.join(dir_path, '.backup')
if os.path.exists(backup_dir):
try:
shutil.rmtree(backup_dir)
cleaned_count += 1
except Exception as e:
failed_paths.append(f"{backup_dir}: {str(e)}")
# 显示结果
result_message = f"成功清理 {cleaned_count} 个备份目录"
if failed_paths:
result_message += f"
清理失败 {len(failed_paths)} 个目录"
result_message += "
失败缘由:
" + "
".join(failed_paths)
style = ttk.Style()
style.configure('RenameSuccess.TLabel', foreground='green')
self.rename_status_label.configure(style='RenameSuccess.TLabel')
self.rename_status_label.configure(text=result_message)
messagebox.showinfo("完成", result_message)
except Exception as e:
error_message = f"清理备份文件时发生错误: {str(e)}"
style = ttk.Style()
style.configure('RenameError.TLabel', foreground='red')
self.rename_status_label.configure(style='RenameError.TLabel')
self.rename_status_label.configure(text=error_message)
messagebox.showerror("错误", error_message)
def show_reward(self):
# 创建新窗口
reward_window = tk.Toplevel(self.root)
reward_window.title("赏赞码")
reward_window.geometry("400x500")
# 加载并显示图片
try:
# 获取资源文件路径
if getattr(sys, 'frozen', False):
# 如果是打包后的exe
base_path = sys._MEIPASS
else:
# 如果是开发环境
base_path = os.path.abspath(os.path.dirname(__file__))
reward_path = os.path.join(base_path, "reward.jpg")
image = Image.open(reward_path)
# 调整图片大小以适应窗口
image = image.resize((300, 300), Image.Resampling.LANCZOS)
photo = ImageTk.PhotoImage(image)
# 创建标签显示图片
image_label = ttk.Label(reward_window, image=photo)
image_label.image = photo # 保持对图片的引用
image_label.pack(pady=20)
# 添加文字提示
text_label = ttk.Label(reward_window, text="您的支持是对作者最大的协助", font=("SimHei", 12))
text_label.pack(pady=10)
# 添加关闭按钮
close_button = ttk.Button(reward_window, text="关闭", command=reward_window.destroy)
close_button.pack(pady=10)
except Exception as e:
messagebox.showerror("错误", f"无法加载赏赞码图片: {str(e)}")
reward_window.destroy()
def on_closing(self):
"""窗口关闭时的处理函数"""
try:
# 遍历所有已知的文件路径
backup_dirs = set()
for file_info in self.all_files_info:
folder = file_info['folder']
backup_dir = os.path.join(folder, '.backup')
if os.path.exists(backup_dir):
backup_dirs.add(backup_dir)
# 清理所有.backup目录
for backup_dir in backup_dirs:
try:
shutil.rmtree(backup_dir)
print(f"已清理临时文件目录: {backup_dir}")
except Exception as e:
print(f"清理临时文件目录失败: {backup_dir}, 错误: {str(e)}")
except Exception as e:
print(f"清理临时文件时发生错误: {str(e)}")
finally:
self.root.destroy()
# 主函数
if __name__ == "__main__":
root = tk.Tk()
app = FileManagementApp(root)
root.mainloop()
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END


















- 最新
- 最热
只看作者