大家好,欢迎来到IT知识分享网。

在处理大量PDF文件时,手动重命名文件不仅耗时,还容易出错。为了提高工作效率,我开发了一个基于Python的图形用户界面(GUI)工具,用于批量重命名PDF文件。这个工具支持多种文件选择方式,包括选择文件、选择文件夹以及拖拽操作,能够满足不同用户的需求。
一、工具的功能
这个工具的主要功能是批量重命名PDF文件。用户可以根据自己的需求设置文件名前缀和起始序号,工具会自动为每个文件生成新的文件名,并在文件名中包含文件夹名称和文件的页数。以下是工具的主要功能特点:
- 多种文件选择方式:
- 选择文件:用户可以通过点击“选择文件”按钮,选择一个或多个PDF文件。
- 选择文件夹:用户可以通过点击“选择文件夹”按钮,选择一个包含PDF文件的文件夹。工具会自动列出该文件夹中的所有PDF文件。
- 拖拽操作:用户可以将文件或文件夹拖拽到指定区域,工具会自动处理拖拽的文件或文件夹中的PDF文件。
- 文件名自定义:
- 用户可以输入自定义的文件名前缀。
- 用户可以设置起始序号,工具会从该序号开始为文件编号。
- 文件名格式:
- 新文件名格式为:文件夹名称_前缀编号_页数.pdf。例如,如果文件夹名称为example,前缀为test,起始序号为1,文件页数为10,则文件名将被重命名为example_test001_10页.pdf。
- 错误处理与用户提示:
- 提供详细的错误提示,帮助用户排查问题。
- 在操作成功时,会弹出提示框告知用户操作成功。
二、代码实现
以下是这个工具的完整代码实现:
import os import tkinter as tk from tkinter import filedialog, messagebox import fitz # PyMuPDF import re # 正则表达式库 from tkinterdnd2 import DND_FILES, TkinterDnD def natural_sort_key(s): """自然排序键函数,用于将文件名按数字、字母和汉字顺序排序""" return [ int(text) if text.isdigit() else text.lower() for text in re.split(r'(\d+)', s) ] def rename_pdfs(): """重命名PDF文件""" pdf_files = file_list.get(0, tk.END) # 获取列表框中的所有PDF文件路径 prefix = prefix_entry.get() start_number = start_number_entry.get() if not pdf_files: messagebox.showerror("错误", "请选择PDF文件或文件夹!") return if not prefix: messagebox.showerror("错误", "请输入用于命名的前缀文字!") return if not start_number.isdigit() or int(start_number) < 1: messagebox.showerror("错误", "请输入有效的起始序号!") return start_number = int(start_number) for i, pdf_path in enumerate(pdf_files, start=start_number): try: doc = fitz.open(pdf_path) # 打开PDF文件 page_count = doc.page_count # 获取页数 doc.close() # 关闭PDF文件 folder_path = os.path.dirname(pdf_path) folder_name = os.path.basename(folder_path) # 获取文件夹名字 file_name = os.path.basename(pdf_path) new_name = f"{folder_name}_{prefix}{i:03d}_{page_count}页.pdf" # 在前缀前面加上文件夹名字 new_path = os.path.join(folder_path, new_name) os.rename(pdf_path, new_path) except Exception as e: messagebox.showerror("错误", f"无法重命名文件 {file_name}:{e}") return messagebox.showinfo("完成", "所有PDF文件已成功重命名。") file_list.delete(0, tk.END) # 清空文件列表框 def select_files(): """选择PDF文件""" file_paths = filedialog.askopenfilenames(title="选择PDF文件", filetypes=[("PDF files", "*.pdf")]) if file_paths: for file_path in file_paths: if file_path not in file_list.get(0, tk.END): file_list.insert(tk.END, file_path) def select_folder(): """选择文件夹""" folder_path = filedialog.askdirectory(title="选择包含PDF文件的文件夹") if folder_path: try: pdf_files = [os.path.join(folder_path, f) for f in os.listdir(folder_path) if f.lower().endswith('.pdf')] pdf_files.sort(key=lambda x: natural_sort_key(os.path.basename(x))) file_list.delete(0, tk.END) for pdf_file in pdf_files: file_list.insert(tk.END, pdf_file) except Exception as e: messagebox.showerror("错误", f"无法读取文件夹内容:{e}") def delete_selected_file(): """删除选中的文件""" selected_indices = file_list.curselection() if selected_indices: for index in reversed(selected_indices): file_list.delete(index) def drop(event): """处理拖拽事件""" file_paths = root.tk.splitlist(event.data) for file_path in file_paths: if os.path.isfile(file_path) and file_path.lower().endswith('.pdf'): if file_path not in file_list.get(0, tk.END): file_list.insert(tk.END, file_path) elif os.path.isdir(file_path): try: pdf_files = [os.path.join(file_path, f) for f in os.listdir(file_path) if f.lower().endswith('.pdf')] pdf_files.sort(key=lambda x: natural_sort_key(os.path.basename(x))) for pdf_file in pdf_files: if pdf_file not in file_list.get(0, tk.END): file_list.insert(tk.END, pdf_file) except Exception as e: messagebox.showerror("错误", f"无法读取文件夹内容:{e}") # 创建主窗口 root = TkinterDnD.Tk() root.title("PDF文件重命名工具") root.geometry("800x600") # 创建一个Frame用于布局 main_frame = tk.Frame(root) main_frame.pack(pady=20) # 文件选择区域 file_label = tk.Label(main_frame, text="选择PDF文件或文件夹:", font=("Arial", 12)) file_label.grid(row=0, column=0, padx=10, pady=10, sticky="w") # 文件列表框 file_list = tk.Listbox(main_frame, width=70, height=10, font=("Arial", 12)) file_list.grid(row=1, column=0, padx=10, pady=10, columnspan=5, sticky="ew") # 添加竖向滚动条 yscrollbar = tk.Scrollbar(main_frame, orient="vertical", command=file_list.yview) yscrollbar.grid(row=1, column=5, padx=0, pady=10, sticky="ns") file_list.config(yscrollcommand=yscrollbar.set) # 添加横向滚动条 xscrollbar = tk.Scrollbar(main_frame, orient="horizontal", command=file_list.xview) xscrollbar.grid(row=2, column=0, padx=10, pady=0, columnspan=5, sticky="ew") file_list.config(xscrollcommand=xscrollbar.set) # 按钮区域 button_frame = tk.Frame(main_frame) button_frame.grid(row=3, column=0, columnspan=5, pady=10) file_button = tk.Button(button_frame, text="选择文件", command=select_files, font=("Arial", 12), width=15) file_button.pack(side=tk.LEFT, padx=10) folder_button = tk.Button(button_frame, text="选择文件夹", command=select_folder, font=("Arial", 12), width=15) folder_button.pack(side=tk.LEFT, padx=10) delete_button = tk.Button(button_frame, text="删除文件", command=delete_selected_file, font=("Arial", 12), width=15) delete_button.pack(side=tk.LEFT, padx=10) rename_button = tk.Button(button_frame, text="开始重命名", command=rename_pdfs, font=("Arial", 12), width=15, bg="#4CAF50", fg="white") rename_button.pack(side=tk.LEFT, padx=10) # 前缀输入区域 prefix_label = tk.Label(main_frame, text="前 缀:", font=("Arial", 12)) prefix_label.grid(row=4, column=0, padx=10, pady=10, sticky="w") prefix_entry = tk.Entry(main_frame, width=50, font=("Arial", 12)) prefix_entry.insert(0, "AHHW-JL-") prefix_entry.grid(row=4, column=1, padx=10, pady=10, columnspan=4, sticky="ew") # 起始序号输入区域 start_number_label = tk.Label(main_frame, text="起始序号:", font=("Arial", 12)) start_number_label.grid(row=5, column=0, padx=10, pady=10, sticky="w") start_number_entry = tk.Entry(main_frame, width=50, font=("Arial", 12)) start_number_entry.insert(0, "1") start_number_entry.grid(row=5, column=1, padx=10, pady=10, columnspan=4, sticky="ew") # 拖拽区域 drag_frame = tk.LabelFrame(main_frame, text="拖拽文件或文件夹到这里", padx=20, pady=20) drag_frame.grid(row=6, column=0, columnspan=5, padx=10, pady=10, sticky="ew") drag_label = tk.Label(drag_frame, text="将文件或文件夹拖拽到这里", font=("Arial", 14), wraplength=780) drag_label.pack(fill="both", expand=True) # 配置拖拽功能 drag_label.drop_target_register(DND_FILES) drag_label.dnd_bind('<<Drop>>', drop) # 运行主循环 root.mainloop()
三、代码片段的详细介绍及特点
(一)自然排序函数
def natural_sort_key(s): """自然排序键函数,用于将文件名按数字、字母和汉字顺序排序""" return [ int(text) if text.isdigit() else text.lower() for text in re.split(r'(\d+)', s) ]
- 功能:这个函数用于对文件名进行自然排序。它将文件名按照数字和非数字部分分开,然后将数字部分转换为整数,非数字部分转换为小写字符串。这样可以确保文件名按照自然顺序排序,例如1.pdf、2.pdf、10.pdf会按1.pdf、2.pdf、10.pdf的顺序排序,而不是按照字典顺序排序。
- 特点:使用正则表达式re.split(r'(\d+)’, s)将文件名拆分为数字和非数字部分,然后通过列表推导式对每个部分进行处理,简洁高效。
(二)重命名PDF文件函数
def rename_pdfs(): """重命名PDF文件""" pdf_files = file_list.get(0, tk.END) # 获取列表框中的所有PDF文件路径 prefix = prefix_entry.get() start_number = start_number_entry.get() if not pdf_files: messagebox.showerror("错误", "请选择PDF文件或文件夹!") return if not prefix: messagebox.showerror("错误", "请输入用于命名的前缀文字!") return if not start_number.isdigit() or int(start_number) < 1: messagebox.showerror("错误", "请输入有效的起始序号!") return start_number = int(start_number) for i, pdf_path in enumerate(pdf_files, start=start_number): try: doc = fitz.open(pdf_path) # 打开PDF文件 page_count = doc.page_count # 获取页数 doc.close() # 关闭PDF文件 folder_path = os.path.dirname(pdf_path) folder_name = os.path.basename(folder_path) # 获取文件夹名字 file_name = os.path.basename(pdf_path) new_name = f"{folder_name}_{prefix}{i:03d}_{page_count}页.pdf" # 在前缀前面加上文件夹名字 new_path = os.path.join(folder_path, new_name) os.rename(pdf_path, new_path) except Exception as e: messagebox.showerror("错误", f"无法重命名文件 {file_name}:{e}") return messagebox.showinfo("完成", "所有PDF文件已成功重命名。") file_list.delete(0, tk.END) # 清空文件列表框
- 功能:这个函数用于重命名PDF文件。它会遍历文件列表框中的所有PDF文件路径,根据用户输入的前缀和起始序号生成新的文件名,并在文件名中包含文件夹名称和文件的页数。然后,它会将每个文件重命名为新的文件名。
- 特点:
- 使用fitz库(PyMuPDF)打开PDF文件,获取文件的页数。
- 使用os.rename函数重命名文件。
- 提供详细的错误提示,帮助用户排查问题。
- 在操作成功时,会弹出提示框告知用户操作成功,并清空文件列表框。
(三)选择文件函数
def select_files(): """选择PDF文件""" file_paths = filedialog.askopenfilenames(title="选择PDF文件", filetypes=[("PDF files", "*.pdf")]) if file_paths: for file_path in file_paths: if file_path not in file_list.get(0, tk.END): file_list.insert(tk.END, file_path)
- 功能:这个函数用于选择PDF文件。它会弹出一个文件选择对话框,让用户选择一个或多个PDF文件。然后,它会将选中的文件路径添加到文件列表框中。
- 特点:
- 使用tkinter库的filedialog.askopenfilenames函数弹出文件选择对话框。
- 检查文件列表框中是否已经存在选中的文件路径,避免重复添加。
(四)选择文件夹函数
def select_folder(): """选择文件夹""" folder_path = filedialog.askdirectory(title="选择包含PDF文件的文件夹") if folder_path: try: pdf_files = [os.path.join(folder_path, f) for f in os.listdir(folder_path) if f.lower().endswith('.pdf')] pdf_files.sort(key=lambda x: natural_sort_key(os.path.basename(x))) file_list.delete(0, tk.END) for pdf_file in pdf_files: file_list.insert(tk.END, pdf_file) except Exception as e: messagebox.showerror("错误", f"无法读取文件夹内容:{e}")
- 功能:这个函数用于选择文件夹。它会弹出一个文件夹选择对话框,让用户选择一个包含PDF文件的文件夹。然后,它会列出该文件夹中的所有PDF文件路径,并将它们添加到文件列表框中。
- 特点:
- 使用tkinter库的filedialog.askdirectory函数弹出文件夹选择对话框。
- 使用os.listdir函数列出文件夹中的所有文件,并过滤出PDF文件。
- 使用natural_sort_key函数对文件名进行自然排序。
- 检查文件列表框中是否已经存在文件路径,避免重复添加。
(五)删除选中的文件函数
def delete_selected_file(): """删除选中的文件""" selected_indices = file_list.curselection() if selected_indices: for index in reversed(selected_indices): file_list.delete(index)
- 功能:这个函数用于删除选中的文件。它会从文件列表框中删除选中的文件路径。
- 特点:
- 使用tkinter库的Listbox组件的curselection方法获取选中的文件索引。
- 使用delete方法删除选中的文件路径。
(六)拖拽事件处理函数
def drop(event): """处理拖拽事件""" file_paths = root.tk.splitlist(event.data) for file_path in file_paths: if os.path.isfile(file_path) and file_path.lower().endswith('.pdf'): if file_path not in file_list.get(0, tk.END): file_list.insert(tk.END, file_path) elif os.path.isdir(file_path): try: pdf_files = [os.path.join(file_path, f) for f in os.listdir(file_path) if f.lower().endswith('.pdf')] pdf_files.sort(key=lambda x: natural_sort_key(os.path.basename(x))) for pdf_file in pdf_files: if pdf_file not in file_list.get(0, tk.END): file_list.insert(tk.END, pdf_file) except Exception as e: messagebox.showerror("错误", f"无法读取文件夹内容:{e}")
- 功能:这个函数用于处理拖拽事件。它会处理拖拽到指定区域的文件或文件夹路径,将PDF文件路径添加到文件列表框中。
- 特点:
- 使用tkinterdnd2库实现拖拽功能。
- 检查拖拽的路径是否是文件或文件夹。
- 如果是文件夹,会列出文件夹中的所有PDF文件路径,并将它们添加到文件列表框中。
- 使用natural_sort_key函数对文件名进行自然排序。
- 检查文件列表框中是否已经存在文件路径,避免重复添加。
(七)主窗口创建
# 创建主窗口 root = TkinterDnD.Tk() root.title("PDF文件重命名工具") root.geometry("800x600") # 创建一个Frame用于布局 main_frame = tk.Frame(root) main_frame.pack(pady=20) # 文件选择区域 file_label = tk.Label(main_frame, text="选择PDF文件或文件夹:", font=("Arial", 12)) file_label.grid(row=0, column=0, padx=10, pady=10, sticky="w") # 文件列表框 file_list = tk.Listbox(main_frame, width=70, height=10, font=("Arial", 12)) file_list.grid(row=1, column=0, padx=10, pady=10, columnspan=5, sticky="ew") # 添加竖向滚动条 yscrollbar = tk.Scrollbar(main_frame, orient="vertical", command=file_list.yview) yscrollbar.grid(row=1, column=5, padx=0, pady=10, sticky="ns") file_list.config(yscrollcommand=yscrollbar.set) # 添加横向滚动条 xscrollbar = tk.Scrollbar(main_frame, orient="horizontal", command=file_list.xview) xscrollbar.grid(row=2, column=0, padx=10, pady=0, columnspan=5, sticky="ew") file_list.config(xscrollcommand=xscrollbar.set) # 按钮区域 button_frame = tk.Frame(main_frame) button_frame.grid(row=3, column=0, columnspan=5, pady=10) file_button = tk.Button(button_frame, text="选择文件", command=select_files, font=("Arial", 12), width=15) file_button.pack(side=tk.LEFT, padx=10) folder_button = tk.Button(button_frame, text="选择文件夹", command=select_folder, font=("Arial", 12), width=15) folder_button.pack(side=tk.LEFT, padx=10) delete_button = tk.Button(button_frame, text="删除文件", command=delete_selected_file, font=("Arial", 12), width=15) delete_button.pack(side=tk.LEFT, padx=10) rename_button = tk.Button(button_frame, text="开始重命名", command=rename_pdfs, font=("Arial", 12), width=15, bg="#4CAF50", fg="white") rename_button.pack(side=tk.LEFT, padx=10) # 前缀输入区域 prefix_label = tk.Label(main_frame, text="前 缀:", font=("Arial", 12)) prefix_label.grid(row=4, column=0, padx=10, pady=10, sticky="w") prefix_entry = tk.Entry(main_frame, width=50, font=("Arial", 12)) prefix_entry.insert(0, "AHHW-JL-") prefix_entry.grid(row=4, column=1, padx=10, pady=10, columnspan=4, sticky="ew") # 起始序号输入区域 start_number_label = tk.Label(main_frame, text="起始序号:", font=("Arial", 12)) start_number_label.grid(row=5, column=0, padx=10, pady=10, sticky="w") start_number_entry = tk.Entry(main_frame, width=50, font=("Arial", 12)) start_number_entry.insert(0, "1") start_number_entry.grid(row=5, column=1, padx=10, pady=10, columnspan=4, sticky="ew") # 拖拽区域 drag_frame = tk.LabelFrame(main_frame, text="拖拽文件或文件夹到这里", padx=20, pady=20) drag_frame.grid(row=6, column=0, columnspan=5, padx=10, pady=10, sticky="ew") drag_label = tk.Label(drag_frame, text="将文件或文件夹拖拽到这里", font=("Arial", 14), wraplength=780) drag_label.pack(fill="both", expand=True) # 配置拖拽功能 drag_label.drop_target_register(DND_FILES) drag_label.dnd_bind('<<Drop>>', drop) # 运行主循环 root.mainloop()
- 功能:这段代码用于创建主窗口,包括文件选择区域、文件列表框、按钮区域、前缀输入区域、起始序号输入区域和拖拽区域。用户可以通过这些组件选择文件夹、选择文件、输入前缀和起始序号、点击重命名按钮或拖拽文件夹或文件到拖拽区域,实现PDF文件的批量重命名。
- 特点:
- 使用tkinter库创建图形用户界面,提供简洁直观的操作界面。
- 使用tkinterdnd2库实现拖拽功能,支持文件夹或文件的拖拽操作。
- 提供文件选择区域,用户可以点击按钮选择文件或文件夹。
- 提供文件列表框,用户可以查看选中的文件路径。
- 提供按钮区域,用户可以点击按钮选择文件、选择文件夹、删除选中的文件或开始重命名操作。
- 提供前缀输入区域和起始序号输入区域,用户可以输入自定义的文件名前缀和起始序号。
- 提供拖拽区域,用户可以将文件或文件夹拖拽到该区域,实现PDF文件的批量重命名。
四、总结
这个基于Python的图形用户界面工具,通过简单的操作即可实现PDF文件的批量重命名。它支持多种文件选择方式,包括选择文件、选择文件夹以及拖拽操作,能够满足不同用户的需求。工具的主要特点包括自然排序、文件名自定义、错误处理与用户提示等。通过使用tkinter、tkinterdnd2和fitz等库,实现了简洁高效的GUI交互和文件处理功能。希望这个工具能够帮助你更高效地完成PDF文件的重命名任务。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/179677.html