最近我用华为手机助手将手机上的几千张照片导出了电脑,打算好好整理一下。然而,一看到这么多照片需要整理,我就有些头疼了。
于是,我决定用Python编写一个小工具,帮助我按“年月”将照片整理到不同的文件夹中。这样一来,照片管理就变得更加轻松有序。
pillow模块安装命令
pip install pillow
代码:
import os import shutil from PIL import Image from PIL.ExifTags import TAGS from tkinter import Tk, Button, Label, filedialog, Checkbutton, Text, Scrollbar, BooleanVar, Frame, END class MediaOrganizer: def __init__(self, root): self.root = root self.root.title("Media Files Organizer") self.selected_folder = None self.tmp = "" self.create_widgets() def create_widgets(self): # 创建Frame来组织复选框和按钮 control_frame = Frame(self.root) control_frame.pack(pady=10) # 创建选择文件夹的按钮 select_button = Button(control_frame, text="选择文件夹", command=self.select_folder) select_button.pack(side='left', padx=5) # 创建复选框 self.audio_var = BooleanVar() self.image_var = BooleanVar() self.video_var = BooleanVar() self.audio_check = Checkbutton(control_frame, text="声音", variable=self.audio_var) self.image_check = Checkbutton(control_frame, text="图片", variable=self.image_var) self.video_check = Checkbutton(control_frame, text="视频", variable=self.video_var) self.audio_check.pack(side='left', padx=5) self.image_check.pack(side='left', padx=5) self.video_check.pack(side='left', padx=5) # 绑定鼠标事件 self.audio_check.bind("<Enter>", lambda event: self.show_tooltip(event, self.audio_check)) self.audio_check.bind("<Leave>", self.hide_tooltip) self.image_check.bind("<Enter>", lambda event: self.show_tooltip(event, self.image_check)) self.image_check.bind("<Leave>", self.hide_tooltip) self.video_check.bind("<Enter>", lambda event: self.show_tooltip(event, self.video_check)) self.video_check.bind("<Leave>", self.hide_tooltip) # 创建开始按钮 start_button = Button(control_frame, text="开始整理", command=self.start_organizing) start_button.pack(side='left', padx=5) # 创建状态标签 self.status_label = Label(self.root, text="将所选文件夹中的媒体文件按照年月分别整理到不同文件夹(例如 202411)中\n需要媒体文件包含EXIF信息,仅整理所选文件夹中的文件,不包含子文件夹") self.status_label.pack(pady=10) # 创建文本框 log_frame = Frame(self.root) log_frame.pack(pady=10, fill='both', expand=True) self.log_text = Text(log_frame, height=20, width=80) self.log_text.pack(side='left', fill='both', expand=True) scrollbar = Scrollbar(log_frame, command=self.log_text.yview) scrollbar.pack(side='right', fill='y') self.log_text.config(yscrollcommand=scrollbar.set) def get_exif_data(self, image_path): try: image = Image.open(image_path) exif_data = image._getexif() if exif_data is None: return None exif = { TAGS[k]: v for k, v in exif_data.items() if k in TAGS } return exif except Exception as e: self.log_text.insert(END, f"读取EXIF数据失败: {e}\n") self.log_text.see(END) self.root.update_idletasks() # 强制更新界面 return None def get_date_taken(self, exif_data): return exif_data.get('DateTimeOriginal', None) def organize_photos(self, folder_path, file_types): for filename in os.listdir(folder_path): if any(filename.lower().endswith(ext) for ext in file_types): file_path = os.path.join(folder_path, filename) exif_data = self.get_exif_data(file_path) if exif_data: date_taken = self.get_date_taken(exif_data) if date_taken: year_month = date_taken[:7].replace(':', '') year_month_folder = os.path.join(folder_path, year_month) if not os.path.exists(year_month_folder): os.makedirs(year_month_folder) shutil.move(file_path, os.path.join(year_month_folder, filename)) self.log_text.insert(END, f"移动 {filename} 到 {year_month_folder}\n") self.log_text.see(END) self.root.update_idletasks() # 强制更新界面 else: self.log_text.insert(END, f"没有日期数据的文件: {filename}\n") self.log_text.see(END) self.root.update_idletasks() # 强制更新界面 else: self.log_text.insert(END, f"没有EXIF的文件: {filename}\n") self.log_text.see(END) self.root.update_idletasks() # 强制更新界面 def select_folder(self): self.selected_folder = filedialog.askdirectory() if self.selected_folder: self.status_label.config(text=f"选择了文件夹: {self.selected_folder}") def start_organizing(self): if self.selected_folder: file_types = [] if self.audio_var.get(): file_types.extend(['.mp3', '.wav', '.flac', '.aac']) if self.image_var.get(): file_types.extend(['.png', '.jpg', '.jpeg', '.tiff', '.bmp', '.gif']) if self.video_var.get(): file_types.extend(['.mp4', '.avi', '.mov', '.mkv']) self.organize_photos(self.selected_folder, file_types) self.status_label.config(text=f"{self.selected_folder} 中的文件整理好了。") else: self.status_label.config(text="请选择一个文件夹。") def show_tooltip(self, event, widget): self.tmp = self.status_label.cget("text") if widget == self.audio_check: self.status_label.config(text="声音文件包括: .mp3, .wav, .flac, .aac") elif widget == self.image_check: self.status_label.config(text="图片文件包括: .png, .jpg, .jpeg, .tiff, .bmp, .gif") elif widget == self.video_check: self.status_label.config(text="视频文件包括: .mp4, .avi, .mov, .mkv") def hide_tooltip(self, event): self.status_label.config(text=self.tmp) if __name__ == "__main__": root = Tk() app = MediaOrganizer(root) root.mainloop()
请求资源或报告无效资源,请点击[反馈中心]