E - New Year Tree

本文介绍了一个结合使用bitset和线段树解决特定问题的算法案例。通过深度优先搜索(DFS)预处理节点顺序,确保子树内的节点连续,从而利用线段树和bitset高效处理区间更新和查询操作。

又是一题bitset+线段树
先dfs弄一弄。让在一个子树的都在一起,然后就是线段树+bitset裸题

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <bitset>
#include <map>

#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ROF(i,a,b) for(int i=a;i>=b;i--)
#define mem(i,a) memset(i,a,sizeof(i))
#define rson mid+1,r,rt<<1|1
#define lson l,mid,rt<<1

#define mp make_pair
#define pb push_back
#define ll long long
#define LL long long
using namespace std;
template <typename T>inline void read(T &_x_){
    _x_=0;bool f=false;char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=!f;ch=getchar();}
    while ('0'<=ch&&ch<='9') {_x_=_x_*10+ch-'0';ch=getchar();}
    if(f) _x_=-_x_;
}
const double eps = 0.0000001;
const int maxn = 4e5+7;
const int mod = 1e9+7;

vector<int>G[maxn];
bitset<61> tree[maxn<<2];
int stp = 0, in[maxn], out[maxn],lazy[maxn<<2];
int n,x,y,z,m,a[maxn];

void dfs(int rt, int f){
    in[rt] = ++stp;
    for(auto& v : G[rt]){
        if(v != f) dfs(v, rt);
    }
    out[rt] = stp;
}

void pushup(int rt){
    tree[rt] = tree[rt<<1]|tree[rt<<1|1];
}

void pushdown(int rt){
    if(lazy[rt]){
        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
        tree[rt<<1].reset();
        tree[rt<<1|1].reset();
        tree[rt<<1][lazy[rt]]=tree[rt<<1|1][lazy[rt]]=1;
        lazy[rt]=0;
    }
}

void update(int l,int r,int rt,int L,int R,int val){
    if(l>=L&&r<=R){
        tree[rt].reset();
        tree[rt][val]=1;
        lazy[rt]=val;
        return;
    }
    pushdown(rt);
    int mid=(l+r)/2;
    if(mid>=L) update(lson,L,R,val);
    if(mid<R) update(rson,L,R,val);
    pushup(rt);
}

bitset<61> query(int l,int r,int rt,int L,int R){
    if(l>=L&&r<=R){
        return tree[rt];
    }
    pushdown(rt);
    int mid=(l+r)/2;
    bitset<61> ans;ans.reset();
    if(mid>=L) ans|=query(lson,L,R);
    if(mid<R) ans|=query(rson,L,R);
    pushup(rt);
    return ans;
}

int main(){
    read(n),read(m);
    FOR(i,1,n) read(a[i]);
    FOR(i,2,n){
        read(x),read(y);
        G[x].pb(y);
        G[y].pb(x);
    }
    dfs(1,0);
    FOR(i,1,n) update(1,n,1,in[i],in[i],a[i]);
    FOR(i,1,m){
        read(x);
        if(x==1){
            read(y),read(z);
            int l=in[y],r=out[y];
            update(1,n,1,l,r,z);
        }else{
            read(y);
            int l=in[y],r=out[y];
            printf("%d\n",query(1,n,1,l,r).count());
        }
    }
    return 0;
}
import os import re import tkinter as tk from tkinter import ttk, filedialog, messagebox import PyPDF2 from datetime import datetime class PDFRenamerApp: def __init__(self, root): self.root = root self.root.title("PDF文件名管理工具") self.root.geometry("900x600") self.root.resizable(True, True) # 设置主题 self.style = ttk.Style() self.style.theme_use("clam") # 初始化变量 self.folder_path = tk.StringVar() self.files = [] self.create_widgets() def create_widgets(self): # 顶部框架 - 文件夹选择 top_frame = ttk.LabelFrame(self.root, text="文件夹选择") top_frame.pack(fill="x", padx=10, pady=5) ttk.Label(top_frame, text="目标文件夹:").grid(row=0, column=0, padx=5, pady=5) ttk.Entry(top_frame, textvariable=self.folder_path, width=50).grid(row=0, column=1, padx=5, pady=5) ttk.Button(top_frame, text="浏览", command=self.browse_folder).grid(row=0, column=2, padx=5, pady=5) ttk.Button(top_frame, text="扫描PDF文件", command=self.scan_pdfs).grid(row=0, column=3, padx=5, pady=5) # 中间框架 - 文件列表和编辑 middle_frame = ttk.LabelFrame(self.root, text="PDF文件列表") middle_frame.pack(fill="both", expand=True, padx=10, pady=5) # 创建表格 self.tree = ttk.Treeview(middle_frame, columns=("orig_name", "fonds", "year", "period", "number", "new_name"), show="headings") # 设置列 self.tree.heading("orig_name", text="原文件名") self.tree.heading("fonds", text="全宗号") self.tree.heading("year", text="年度") self.tree.heading("period", text="保管期限") self.tree.heading("number", text="件号") self.tree.heading("new_name", text="新文件名") # 设置列宽 self.tree.column("orig_name", width=200) self.tree.column("fonds", width=80) self.tree.column("year", width=60) self.tree.column("period", width=80) self.tree.column("number", width=80) self.tree.column("new_name", width=250) # 添加滚动条 scrollbar = ttk.Scrollbar(middle_frame, orient="vertical", command=self.tree.yview) self.tree.configure(yscrollcommand=scrollbar.set) self.tree.pack(side="left", fill="both", expand=True) scrollbar.pack(side="right", fill="y") # 底部框架 - 操作按钮 bottom_frame = ttk.Frame(self.root) bottom_frame.pack(fill="x", padx=10, pady=10) ttk.Button(bottom_frame, text="批量重命名", command=self.batch_rename).pack(side="left", padx=5) ttk.Button(bottom_frame, text="导出CSV", command=self.export_csv).pack(side="left", padx=5) ttk.Button(bottom_frame, text="导入CSV", command=self.import_csv).pack(side="left", padx=5) ttk.Button(bottom_frame, text="自动提取元数据", command=self.extract_metadata).pack(side="left", padx=5) ttk.Button(bottom_frame, text="清空列表", command=self.clear_list).pack(side="left", padx=5) ttk.Button(bottom_frame, text="退出", command=self.root.quit).pack(side="right", padx=5) # 绑定双击事件编辑单元格 self.tree.bind("<Double-1>", self.on_double_click) def browse_folder(self): folder_selected = filedialog.askdirectory() if folder_selected: self.folder_path.set(folder_selected) def scan_pdfs(self): folder = self.folder_path.get() if not folder or not os.path.isdir(folder): messagebox.showerror("错误", "请选择有效的文件夹路径") return # 清空现有列表 for item in self.tree.get_children(): self.tree.delete(item) # 扫描PDF文件 self.files = [] for filename in os.listdir(folder): if filename.lower().endswith(".pdf"): file_path = os.path.join(folder, filename) self.files.append({ "orig_path": file_path, "fonds": "", "year": datetime.now().year, "period": "Y", # 默认保管期限为永久 "number": "", "new_name": "" }) # 添加到列表 self.tree.insert("", "end", values=( filename, "", datetime.now().year, "Y", "", "" )) messagebox.showinfo("完成", f"找到 {len(self.files)} 个PDF文件") def on_double_click(self, event): # 获取选中的行和列 region = self.tree.identify("region", event.x, event.y) if region != "cell": return column = self.tree.identify_column(event.x) row_id = self.tree.focus() # 排除原文件名和新文件名列 if column == "#1" or column == "#6": return # 获取当前值 current_values = self.tree.item(row_id, "values") col_index = int(column[1:]) - 1 # 列索引 # 创建编辑框 x, y, width, height = self.tree.bbox(row_id, column) # 创建编辑框 entry_edit = ttk.Entry(self.tree) entry_edit.place(x=x, y=y, width=width, height=height) entry_edit.insert(0, current_values[col_index]) entry_edit.select_range(0, tk.END) entry_edit.focus() # 保存编辑 def save_edit(event=None): new_value = entry_edit.get() # 验证输入 if col_index == 1: # 全宗号 if not re.match(r'^\d{4}$', new_value): messagebox.showerror("错误", "全宗号必须是4位数字") entry_edit.destroy() return elif col_index == 2: # 年度 if not re.match(r'^\d{4}$', new_value): messagebox.showerror("错误", "年度必须是4位数字") entry_edit.destroy() return elif col_index == 3: # 保管期限 if new_value not in ["Y", "C", "D"]: messagebox.showerror("错误", "保管期限必须是Y(永久), C(长期)或D(短期)") entry_edit.destroy() return elif col_index == 4: # 件号 if not re.match(r'^\d{1,5}$', new_value): messagebox.showerror("错误", "件号必须是1-5位数字") entry_edit.destroy() return # 补零到5位 new_value = new_value.zfill(5) # 更新值 new_values = list(current_values) new_values[col_index] = new_value # 生成新文件名 if new_values[1] and new_values[2] and new_values[3] and new_values[4]: new_values[5] = f"{new_values[1]}-WS·{new_values[2]}-{new_values[3]}-{new_values[4]}.pdf" self.tree.item(row_id, values=new_values) entry_edit.destroy() # 更新文件列表 index = self.tree.index(row_id) if index < len(self.files): self.files[index]["fonds"] = new_values[1] self.files[index]["year"] = new_values[2] self.files[index]["period"] = new_values[3] self.files[index]["number"] = new_values[4] self.files[index]["new_name"] = new_values[5] entry_edit.bind("<Return>", save_edit) entry_edit.bind("<FocusOut>", lambda e: save_edit()) def batch_rename(self): if not self.files: messagebox.showwarning("警告", "没有要重命名的文件") return folder = self.folder_path.get() if not folder or not os.path.isdir(folder): messagebox.showerror("错误", "请选择有效的文件夹路径") return success_count = 0 error_count = 0 for file_info in self.files: if not file_info["new_name"]: error_count += 1 continue orig_path = file_info["orig_path"] new_path = os.path.join(folder, file_info["new_name"]) try: os.rename(orig_path, new_path) success_count += 1 # 更新原路径 file_info["orig_path"] = new_path except Exception as e: error_count += 1 print(f"重命名失败: {str(e)}") # 更新列表显示 for idx, file_info in enumerate(self.files): orig_name = os.path.basename(file_info["orig_path"]) self.tree.item(self.tree.get_children()[idx], values=( orig_name, file_info["fonds"], file_info["year"], file_info["period"], file_info["number"], file_info["new_name"] )) messagebox.showinfo("完成", f"成功重命名 {success_count} 个文件\n失败 {error_count} 个文件") def export_csv(self): if not self.files: messagebox.showwarning("警告", "没有可导出的数据") return file_path = filedialog.asksaveasfilename( defaultextension=".csv", filetypes=[("CSV文件", "*.csv")] ) if not file_path: return try: with open(file_path, "w", encoding="utf-8") as f: f.write("原文件名,全宗号,年度,保管期限,件号,新文件名\n") for file_info in self.files: orig_name = os.path.basename(file_info["orig_path"]) f.write(f"{orig_name},{file_info['fonds']},{file_info['year']},{file_info['period']},{file_info['number']},{file_info['new_name']}\n") messagebox.showinfo("成功", "数据已成功导出到CSV文件") except Exception as e: messagebox.showerror("错误", f"导出失败: {str(e)}") def import_csv(self): file_path = filedialog.askopenfilename( filetypes=[("CSV文件", "*.csv")] ) if not file_path: return try: with open(file_path, "r", encoding="utf-8") as f: lines = f.readlines() # 清空现有列表 for item in self.tree.get_children(): self.tree.delete(item) self.files = [] # 处理数据行 for line in lines[1:]: # 跳过标题行 parts = line.strip().split(",") if len(parts) < 6: continue orig_name, fonds, year, period, number, new_name = parts # 验证数据 if not (re.match(r'^\d{4}$', fonds) and re.match(r'^\d{4}$', year) and period in ["Y", "C", "D"] and re.match(r'^\d{5}$', number)): continue # 添加到列表 self.files.append({ "orig_path": os.path.join(self.folder_path.get(), orig_name), "fonds": fonds, "year": year, "period": period, "number": number, "new_name": new_name }) self.tree.insert("", "end", values=( orig_name, fonds, year, period, number, new_name )) messagebox.showinfo("成功", f"成功导入 {len(self.files)} 条记录") except Exception as e: messagebox.showerror("错误", f"导入失败: {str(e)}") def extract_metadata(self): if not self.files: messagebox.showwarning("警告", "没有可处理的文件") return for idx, file_info in enumerate(self.files): try: with open(file_info["orig_path"], "rb") as f: pdf_reader = PyPDF2.PdfReader(f) # 尝试从元数据中获取信息 meta = pdf_reader.metadata # 尝试从文本中提取信息 text = "" for page in pdf_reader.pages: text += page.extract_text() + " " # 提取全宗号 - 尝试从文本中找到4位数字 fonds_match = re.search(r'\b(\d{4})\b', text) if fonds_match: file_info["fonds"] = fonds_match.group(1) # 提取年度 - 尝试找到4位数字的年份 year_match = re.search(r'\b(20\d{2})\b', text) if year_match: file_info["year"] = year_match.group(1) # 提取件号 - 尝试找到5位数字 number_match = re.search(r'\b(\d{5})\b', text) if number_match: file_info["number"] = number_match.group(1) # 生成新文件名 if file_info["fonds"] and file_info["year"] and file_info["period"] and file_info["number"]: file_info["new_name"] = f"{file_info['fonds']}-WS·{file_info['year']}-{file_info['period']}-{file_info['number']}.pdf" # 更新列表显示 orig_name = os.path.basename(file_info["orig_path"]) self.tree.item(self.tree.get_children()[idx], values=( orig_name, file_info["fonds"], file_info["year"], file_info["period"], file_info["number"], file_info["new_name"] )) except Exception as e: print(f"处理文件 {file_info['orig_path']} 时出错: {str(e)}") messagebox.showinfo("完成", "元数据提取完成") def clear_list(self): for item in self.tree.get_children(): self.tree.delete(item) self.files = [] messagebox.showinfo("完成", "文件列表已清空") if __name__ == "__main__": root = tk.Tk() app = PDFRenamerApp(root) root.mainloop() 这种不行
最新发布
12-06
<think>由于用户的问题是关于优化使用tkinter和PyPDF2实现的PDF文件名管理工具代码,我们将从以下几个方面考虑优化: 1. 代码结构优化:将功能模块化,提高可读性和可维护性。 2. 异常处理:增强程序的健壮性,处理可能出现的异常情况。 3. 用户体验:改进GUI界面,使其更加友好。 4. 性能优化:处理大文件时的性能问题,避免界面假死(例如使用多线程)。 5. 功能扩展:增加一些实用功能,如批量处理、进度显示等。 假设原始代码的基本功能包括: - 通过tkinter选择文件夹 - 遍历文件夹中的PDF文件 - 使用PyPDF2读取PDF的标题(或其他元数据)并重命名文件 以下是一个优化后的代码示例,包括上述优化点: ### 优化点说明: 1. 使用类来组织代码,便于管理状态和功能。 2. 将GUI创建、文件处理等分离成不同的方法。 3. 使用多线程处理文件重命名,避免GUI界面假死。 4. 添加进度条显示处理进度。 5. 增强错误处理,例如跳过无法读取的PDF文件。 6. 提供用户反馈,如状态标签和消息框。 ### 代码优化示例 ```python import os import threading from tkinter import * from tkinter import filedialog, messagebox, ttk from PyPDF2 import PdfFileReader, utils class PDFRenamerApp: def __init__(self, root): self.root = root self.root.title("PDF文件名管理器") self.root.geometry("500x300") self.folder_path = StringVar() self.status_text = StringVar() self.status_text.set("准备就绪") self.progress = DoubleVar() self.create_widgets() def create_widgets(self): # 文件夹选择部分 frame_folder = Frame(self.root) frame_folder.pack(pady=10) Label(frame_folder, text="目标文件夹:").pack(side=LEFT, padx=5) Entry(frame_folder, textvariable=self.folder_path, width=40).pack(side=LEFT, padx=5) Button(frame_folder, text="浏览", command=self.browse_folder).pack(side=LEFT, padx=5) # 进度条 frame_progress = Frame(self.root) frame_progress.pack(fill=X, padx=10, pady=10) Label(frame_progress, textvariable=self.status_text).pack(anchor=W) ttk.Progressbar(frame_progress, variable=self.progress, maximum=100).pack(fill=X, pady=5) # 按钮 frame_btn = Frame(self.root) frame_btn.pack(pady=10) Button(frame_btn, text="开始重命名", command=self.start_renaming).pack(side=LEFT, padx=10) Button(frame_btn, text="退出", command=self.root.quit).pack(side=LEFT, padx=10) def browse_folder(self): folder_selected = filedialog.askdirectory() if folder_selected: self.folder_path.set(folder_selected) def start_renaming(self): folder = self.folder_path.get() if not folder: messagebox.showwarning("警告", "请先选择文件夹!") return # 使用线程处理,避免界面卡住 thread = threading.Thread(target=self.rename_pdfs, args=(folder,)) thread.daemon = True thread.start() def rename_pdfs(self, folder): try: pdf_files = [f for f in os.listdir(folder) if f.lower().endswith('.pdf')] total = len(pdf_files) if total == 0: self.status_text.set("未找到PDF文件") return self.progress.set(0) for i, filename in enumerate(pdf_files): full_path = os.path.join(folder, filename) new_name = None try: # 读取PDF文档信息 with open(full_path, 'rb') as f: reader = PdfFileReader(f) # 获取文档信息,尝试获取标题 info = reader.getDocumentInfo() title = info.title # 如果标题存在且非空,则使用标题作为新文件名 if title and title.strip(): # 去除非法字符 new_name = ''.join(c for c in title if c not in r'\/:*?"<>|').strip() new_name += '.pdf' else: # 如果没有标题,则尝试从第一页提取文本(这里简单处理,实际可能需要更复杂的方法) # 注意:这里仅示例,提取文本可能不准确,且可能很长 page = reader.getPage(0) text = page.extractText().splitlines()[0] if page else None if text: new_name = text[:50] + '.pdf' # 截取前50个字符 else: new_name = filename # 保留原名 except utils.PdfReadError: new_name = filename # 读取错误则保留原名 except Exception as e: print(f"处理文件{filename}出错: {e}") new_name = filename # 构建新路径 new_path = os.path.join(folder, new_name) # 避免重名 if new_path != full_path: if os.path.exists(new_path): base, ext = os.path.splitext(new_name) counter = 1 while os.path.exists(os.path.join(folder, f"{base}_{counter}{ext}")): counter += 1 new_name = f"{base}_{counter}{ext}" new_path = os.path.join(folder, new_name) os.rename(full_path, new_path) # 更新进度 self.progress.set((i+1) / total * 100) self.status_text.set(f"处理中: {i+1}/{total}") self.status_text.set("处理完成") messagebox.showinfo("完成", "所有PDF文件处理完成!") except Exception as e: messagebox.showerror("错误", f"发生错误: {e}") self.status_text.set("错误发生") # 主程序 if __name__ == "__main__": root = Tk() app = PDFRenamerApp(root) root.mainloop() ``` ### 优化说明: 1. **模块化**:使用类封装,使代码结构更清晰。 2. **多线程**:文件处理在单独线程中进行,避免GUI界面卡住。 3. **进度反馈**:添加进度条和状态文本,让用户知道处理进度。 4. **错误处理**:捕获PDF读取中可能出现的异常,跳过问题文件,避免程序崩溃。 5. **文件名合法性**:去除文件名中的非法字符。 6. **重名处理**:如果新文件名已存在,自动在文件名后添加序号。 ### 注意事项: - 由于PyPDF2在读取某些PDF文件时可能会遇到问题(例如加密文件),因此需要捕获异常。 - 使用多线程时,注意线程安全,避免在子线程中直接操作GUI组件(这里通过线程安全的方式更新进度条和状态文本)。 ### 进一步优化建议: - 可以增加日志记录功能,记录重命名的成功和失败情况。 - 对于加密的PDF文件,可以尝试提供密码输入支持(但需要用户交互,这里暂未实现)。 - 如果PDF没有标题,从第一页提取文本作为文件名可能不够理想,可以考虑其他方法(如使用文件内容摘要等)。 希望这个优化版本对您有所帮助! </think> 以下是对使用tkinter和PyPDF2实现的PDF文件名管理工具的优化建议,包括代码结构优化、性能提升和用户体验改进: ### 主要优化方案 1. **异步处理与线程优化**(避免GUI冻结) ```python import threading # 在重命名函数中添加 def rename_files(): thread = threading.Thread(target=actual_renaming) thread.start() def actual_renaming(): # 实际的重命名逻辑 # 更新GUI使用after()方法 root.after(0, update_progress_bar) ``` 2. **PDF元数据读取优化** ```python from PyPDF2 import PdfReader def get_pdf_title(file_path): try: with open(file_path, 'rb') as f: reader = PdfReader(f) meta = reader.metadata title = meta.get('/Title') or os.path.basename(file_path) # 过滤非法文件名字符 return re.sub(r'[\\/*?:"<>|]', "", title.strip()) + ".pdf" except Exception as e: return f"Error_{os.path.basename(file_path)}" ``` 3. **UI/UX 增强** ```python # 添加进度条 ttk.Progressbar(root, variable=progress_var, length=300).pack(pady=5) # 添加状态标签 status_label = Label(root, text="就绪", fg="blue") status_label.pack(pady=5) # 添加日志框 log_text = Text(root, height=10, width=50) log_text.pack(pady=10) ``` 4. **代码结构优化(类封装)** ```python class PDFRenamerApp: def __init__(self, root): self.root = root self.setup_ui() def setup_ui(self): # UI初始化代码 self.btn_select = Button(self.root, text="选择文件夹", command=self.select_folder) def select_folder(self): # 文件夹选择逻辑 ``` ### 完整优化代码示例 ```python import os import re import threading import tkinter as tk from tkinter import filedialog, ttk from PyPDF2 import PdfReader class PDFRenamerApp: def __init__(self, root): self.root = root self.root.title("PDF文件名管理工具") self.root.geometry("600x500") self.setup_ui() self.progress_var = tk.DoubleVar() self.status_var = tk.StringVar(value="就绪") def setup_ui(self): # 文件夹选择区域 frame = tk.Frame(self.root) frame.pack(pady=10, fill=tk.X) tk.Label(frame, text="目标文件夹:").pack(side=tk.LEFT) self.folder_path = tk.Entry(frame, width=40) self.folder_path.pack(side=tk.LEFT, padx=5) tk.Button(frame, text="浏览", command=self.select_folder).pack(side=tk.LEFT) # 控制按钮 btn_frame = tk.Frame(self.root) btn_frame.pack(pady=10) tk.Button(btn_frame, text="开始重命名", command=self.start_renaming).pack(side=tk.LEFT, padx=10) # 进度条 ttk.Progressbar(self.root, variable=self.progress_var, length=550).pack(pady=5) # 状态显示 tk.Label(self.root, textvariable=self.status_var, fg="blue").pack() # 日志框 self.log_text = tk.Text(self.root, height=15, width=70) self.log_text.pack(pady=10, padx=10) self.log_text.insert(tk.END, "操作日志:\n") def select_folder(self): folder = filedialog.askdirectory() if folder: self.folder_path.delete(0, tk.END) self.folder_path.insert(0, folder) def log_message(self, message): self.log_text.insert(tk.END, message + "\n") self.log_text.see(tk.END) def start_renaming(self): folder = self.folder_path.get() if not os.path.isdir(folder): self.status_var.set("错误: 无效文件夹路径") return self.status_var.set("处理中...") thread = threading.Thread(target=self.rename_pdfs, args=(folder,)) thread.daemon = True thread.start() def rename_pdfs(self, folder): try: pdf_files = [f for f in os.listdir(folder) if f.lower().endswith('.pdf')] total = len(pdf_files) for idx, filename in enumerate(pdf_files): old_path = os.path.join(folder, filename) new_name = self.get_pdf_title(old_path) new_path = os.path.join(folder, new_name) # 避免重名冲突 counter = 1 while os.path.exists(new_path): base, ext = os.path.splitext(new_name) new_path = os.path.join(folder, f"{base}_{counter}{ext}") counter += 1 os.rename(old_path, new_path) self.log_message(f"重命名: {filename} -> {os.path.basename(new_path)}") # 更新进度 progress = (idx + 1) / total * 100 self.root.after(0, lambda: self.progress_var.set(progress)) self.root.after(0, lambda: self.status_var.set(f"完成! 已处理 {total} 个文件")) except Exception as e: self.root.after(0, lambda: self.status_var.set(f"错误: {str(e)}")) self.log_message(f"错误: {str(e)}") def get_pdf_title(self, file_path): try: with open(file_path, 'rb') as f: reader = PdfReader(f) title = reader.metadata.get('/Title', '') if not title: # 尝试从第一页提取 page = reader.pages[0] title = page.extract_text().strip().split('\n')[0][:50] # 清理文件名 clean_title = re.sub(r'[\\/*?:"<>|]', '', title).strip() return clean_title + ".pdf" if clean_title else os.path.basename(file_path) except Exception: return os.path.basename(file_path) if __name__ == "__main__": root = tk.Tk() app = PDFRenamerApp(root) root.mainloop() ``` ### 关键优化点说明 1. **异步处理**: - 使用`threading`分离文件操作和GUI主线程 - 通过`after()`方法安全更新UI组件[^1] 2. **PDF处理增强**: - 元数据备用方案:当标题不存在时提取文本首行 - 文件名清理:正则表达式移除非法字符`[\\/*?:"<>|]` - 错误隔离:单文件错误不影响整体流程 3. **用户体验提升**: - 实时进度条显示处理进度 - 滚动日志框显示详细操作记录 - 状态栏反馈当前操作状态 - 文件名冲突处理(自动添加序号) 4. **代码质量优化**: - 面向对象封装提高可维护性 - 异常处理增强程序健壮性 - 模块化设计便于功能扩展 5. **性能考虑**: - 批量处理时内存管理优化 - 避免重复计算文件列表 - 快速失败机制减少无效操作 ### 使用建议 1. 对于加密PDF文件,可添加密码输入功能 2. 增加文件过滤规则(按大小/日期) 3. 添加撤消重命名功能(操作前备份原文件名) 4. 支持自定义命名规则模板(如添加前缀/日期)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值