Python重復(fù)文件批量整理工具的設(shè)計(jì)與實(shí)現(xiàn)
1. 簡(jiǎn)介
這款文件整理工具主要用于在文件夾內(nèi)對(duì)文件進(jìn)行去重和分類存儲(chǔ),尤其適用于處理圖片等文件類型。用戶可以通過(guò)選擇源目錄、目標(biāo)目錄、重復(fù)文件目錄以及非重復(fù)文件目錄,快速完成文件分類和去重工作。工具支持讀取 MD5 列表來(lái)識(shí)別重復(fù)文件,并根據(jù)文件的修改時(shí)間進(jìn)行分類存儲(chǔ)。此外,工具還支持多線程處理,避免界面卡頓,提升用戶體驗(yàn)。
功能
1.目錄選擇和配置:
- 支持設(shè)置基準(zhǔn)目錄、目標(biāo)目錄、重復(fù)文件目錄和非重復(fù)文件目錄。
- 支持通過(guò)瀏覽按鈕快速選擇文件夾路徑。
2.文件去重和分類:
- 使用 MD5 校驗(yàn)碼對(duì)文件進(jìn)行去重,判斷文件是否重復(fù)。
- 如果啟用了 MD5 列表,工具會(huì)加載先前保存的 MD5 列表,以加速去重過(guò)程。
- 根據(jù)文件的修改時(shí)間,自動(dòng)將文件按年和月分類存儲(chǔ)。
3.多線程處理:
- 采用多線程技術(shù),使得文件處理過(guò)程不阻塞主線程,確保界面保持響應(yīng)。
- 文件的移動(dòng)操作在后臺(tái)線程中進(jìn)行,避免影響 UI 界面的流暢性。
4.支持圖片文件類型:
- 支持常見圖片格式,如 JPEG、PNG、BMP 和 HEIC。
- 對(duì) HEIC 文件進(jìn)行特殊處理,提取文件的 EXIF 時(shí)間戳,作為文件分類的依據(jù)。
5.日志記錄:
- 提供實(shí)時(shí)日志記錄功能,記錄文件處理的詳細(xì)過(guò)程。
- 支持日志批量更新,減少對(duì) UI 的頻繁更新,提高性能。
6.MD5 列表管理:
可加載和保存 MD5 列表,記錄基準(zhǔn)文件的 MD5 值,幫助后續(xù)識(shí)別重復(fù)文件。
使用方法
配置目錄:
- 啟動(dòng)工具后,首先配置四個(gè)文件夾路徑:
- 基準(zhǔn)目錄:包含待處理文件的源目錄。
- 目標(biāo)目錄:包含待比對(duì)的目標(biāo)文件夾。
- 重復(fù)文件目錄:存放重復(fù)文件的目錄。
- 非重復(fù)文件目錄:存放未重復(fù)文件的目錄。
選擇選項(xiàng):
- 啟用“讀取 MD5 列表”選項(xiàng)來(lái)加載已保存的 MD5 列表。
- 啟用“啟用分類存儲(chǔ)”選項(xiàng)將文件按年和月進(jìn)行分類存儲(chǔ)。
開始處理:
- 點(diǎn)擊“開始處理”按鈕,工具會(huì)自動(dòng)掃描源目錄和目標(biāo)目錄,識(shí)別重復(fù)文件并進(jìn)行分類存儲(chǔ)。
- 處理過(guò)程中,工具會(huì)在日志框中顯示詳細(xì)的操作信息。
文件分類與去重:
- 工具根據(jù)文件的 MD5 校驗(yàn)碼判斷是否為重復(fù)文件,重復(fù)文件將移動(dòng)到指定的“重復(fù)文件目錄”。
- 未重復(fù)的文件將按其修改時(shí)間(年月)分類,存放到指定的“非重復(fù)文件目錄”中。
完成處理:
文件處理完成后,工具會(huì)在日志框中顯示相關(guān)信息,并自動(dòng)保存更新的 MD5 列表到“非重復(fù)文件目錄”中。
2. 運(yùn)行效果
3.相關(guān)源碼
import os import hashlib import shutil import json import threading import re import io import exifread import tkinter as tk from tkinter import ttk, filedialog, messagebox from datetime import datetime from PIL import Image from PIL.ExifTags import TAGS import pillow_heif from pillow_heif import register_heif_opener class FileOrganizerApp: def __init__(self, root): self.root = root self.root.title("文件整理工具") # 變量初始化 self.base_dir = tk.StringVar() self.target_dir = tk.StringVar() self.duplicate_dir = tk.StringVar() self.unique_dir = tk.StringVar() self.enable_classify = tk.BooleanVar(value=True) self.enable_md5list = tk.BooleanVar(value=False) self.dictfile_name = "base_md5_list.txt" # 創(chuàng)建register_heif_opener模塊里的一個(gè)類然后再Image.open打開HEIC文件 register_heif_opener() # 創(chuàng)建界面組件 self.create_widgets() def create_widgets(self): # 目錄選擇部分 dir_frame = ttk.LabelFrame(self.root, text="目錄配置") dir_frame.pack(padx=10, pady=5, fill=tk.X) self.create_dir_selector(dir_frame, "基準(zhǔn)目錄:", self.base_dir, 0) self.create_dir_selector(dir_frame, "目標(biāo)目錄:", self.target_dir, 1) self.create_dir_selector(dir_frame, "重復(fù)文件目錄:", self.duplicate_dir, 2) self.create_dir_selector(dir_frame, "非重復(fù)文件目錄:", self.unique_dir, 3) # 選項(xiàng)配置 opt_frame = ttk.LabelFrame(self.root, text="選項(xiàng)配置") opt_frame.pack(padx=10, pady=5, fill=tk.X) ttk.Checkbutton(opt_frame, text="啟用分類存儲(chǔ)", variable=self.enable_classify).pack(anchor=tk.W) ttk.Checkbutton(opt_frame, text="讀取MD5列表", variable=self.enable_md5list).pack(anchor=tk.W) # 操作按鈕 btn_frame = ttk.Frame(self.root) btn_frame.pack(padx=10, pady=5, fill=tk.X) ttk.Button(btn_frame, text="開始處理", command=self.start_processing).pack(side=tk.LEFT) # 日志顯示 self.log_text = tk.Text(self.root, height=15) self.scrollbar = tk.Scrollbar(root, command=self.log_text.yview) self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.log_text.config(yscrollcommand=self.scrollbar.set) self.log_text.pack(padx=10, pady=5, fill=tk.BOTH, expand=True) def create_dir_selector(self, parent, label, var, row): frame = ttk.Frame(parent) frame.grid(row=row, column=0, sticky="ew", padx=5, pady=2) ttk.Label(frame, text=label).pack(side=tk.LEFT) entry = ttk.Entry(frame, textvariable=var, width=40) entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5) ttk.Button(frame, text="瀏覽...", command=lambda: self.select_directory(var)).pack(side=tk.LEFT) def select_directory(self, var): dir_path = filedialog.askdirectory() if dir_path: var.set(dir_path) def log(self, message): # 批量更新日志,減少頻繁刷新UI self.log_text.insert(tk.END, message + "\n") self.root.update_idletasks() def calculate_md5(self, filepath): hash_md5 = hashlib.md5() with open(filepath, "rb") as f: for chunk in iter(lambda: f.read(4096), b""): hash_md5.update(chunk) return hash_md5.hexdigest() def save_dict_to_file(self, dictionary, file_path): with open(file_path, 'w', encoding='utf-8') as file: json.dump(dictionary, file, ensure_ascii=False, indent=4) def load_dict_from_file(self, file_path): with open(file_path, 'r', encoding='utf-8') as file: return json.load(file) def get_unique_filename(self, dest_dir, filename): base, ext = os.path.splitext(filename) counter = 1 new_name = filename while os.path.exists(os.path.join(dest_dir, new_name)): new_name = f"{base}_{counter}{ext}" counter += 1 return new_name def is_image(self, file_path): ext = os.path.splitext(file_path)[1].lower() return ext in [".jpg", ".jpeg", ".png", ".bmp", ".heic"] def get_file_time(self, file_path): mtime = os.path.getmtime(file_path) ext = os.path.splitext(file_path)[1].lower() if self.is_image(file_path): if ext == ".heic": mtime = self.get_heic_original(file_path) mtime = self.replace_limited(mtime, ':', '-', 2) dt_object = datetime.strptime(mtime, "%Y-%m-%d %H:%M:%S") mtime = dt_object.timestamp() else: with open(file_path, 'rb') as f: tags = exifread.process_file(f, details=False) if 'EXIF DateTimeOriginal' in tags: mtime = str(tags['EXIF DateTimeOriginal']) mtime = self.replace_limited(mtime, ':', '-', 2) dt_object = datetime.strptime(mtime, "%Y-%m-%d %H:%M:%S") mtime = dt_object.timestamp() return mtime def process_files(self): base_files = {} if self.enable_md5list.get(): base_md5_path = os.path.join(self.base_dir.get(), self.dictfile_name) if os.path.exists(base_md5_path): base_files = self.load_dict_from_file(base_md5_path) self.log(f"基準(zhǔn)MD5已加載: {base_md5_path}") else: for root, _, files in os.walk(self.base_dir.get()): for file in files: path = os.path.join(root, file) md5 = self.calculate_md5(path) base_files[md5] = file self.log(f"基準(zhǔn)文件已掃描: {path}") for root, _, files in os.walk(self.target_dir.get()): for file in files: src_path = os.path.join(root, file) md5 = self.calculate_md5(src_path) self.log(f"正在處理: {src_path}") if md5 in base_files: dest_dir = self.duplicate_dir.get() dest_path = os.path.join(dest_dir, self.get_unique_filename(dest_dir, file)) shutil.move(src_path, dest_path) self.log(f"重復(fù)文件已移動(dòng): {dest_path}") else: if self.enable_classify.get(): mtime = self.get_file_time(src_path) date_dir_Y = datetime.fromtimestamp(mtime).strftime("%Y") date_dir_m = datetime.fromtimestamp(mtime).strftime("%m") dest_dir = os.path.join(self.unique_dir.get(), date_dir_Y, date_dir_m) else: dest_dir = self.unique_dir.get() os.makedirs(dest_dir, exist_ok=True) dest_path = os.path.join(dest_dir, self.get_unique_filename(dest_dir, file)) shutil.move(src_path, dest_path) self.log(f"非重復(fù)文件已移動(dòng): {dest_path}") dest_md5_path = os.path.join(self.unique_dir.get(), self.dictfile_name) self.save_dict_to_file(base_files, dest_md5_path) self.log(f"基準(zhǔn)MD5已輸出: {dest_md5_path}") def start_processing(self): try: dirs = [ self.base_dir.get(), self.target_dir.get(), self.duplicate_dir.get(), self.unique_dir.get() ] for d in dirs: if not d: raise ValueError("所有目錄都必須設(shè)置") os.makedirs(d, exist_ok=True) # 啟動(dòng)新線程處理文件 threading.Thread(target=self.process_files, daemon=True).start() messagebox.showinfo("完成", "文件處理已開始,請(qǐng)稍候!") except Exception as e: messagebox.showerror("錯(cuò)誤", str(e)) self.log(f"錯(cuò)誤發(fā)生: {str(e)}") if __name__ == "__main__": root = tk.Tk() app = FileOrganizerApp(root) root.mainloop()
4.總結(jié)
這款文件整理工具是一個(gè)高效且易于使用的文件去重和分類存儲(chǔ)工具。它結(jié)合了 MD5 校驗(yàn)和文件時(shí)間戳分類,確保用戶能夠快速識(shí)別重復(fù)文件并將文件按時(shí)間進(jìn)行合理分類。工具采用了多線程技術(shù),有效避免了長(zhǎng)時(shí)間操作導(dǎo)致的界面卡頓,提供了流暢的用戶體驗(yàn)。通過(guò)日志記錄和 MD5 列表管理,用戶可以清晰地了解文件處理的每一步操作。此外,該工具支持多種常見的圖片格式,且對(duì) HEIC 文件進(jìn)行了專門的處理,使其適應(yīng)了現(xiàn)代文件管理的需求。
以上就是Python重復(fù)文件批量整理工具的設(shè)計(jì)與實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Python整理重復(fù)文件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
PyCharm活動(dòng)模板設(shè)置步驟實(shí)現(xiàn)
很多情況,我們?cè)趯懘a都會(huì)存在經(jīng)常要寫一些簡(jiǎn)單且又重復(fù)的代碼,Pycharm中的活動(dòng)模板可以把這些使用頻率很高的一些代碼打包起來(lái)設(shè)置一個(gè)快捷鍵,本文就來(lái)介紹一下如何實(shí)現(xiàn)2023-12-12Python實(shí)現(xiàn)輸出某區(qū)間范圍內(nèi)全部素?cái)?shù)的方法
這篇文章主要介紹了Python實(shí)現(xiàn)輸出某區(qū)間范圍內(nèi)全部素?cái)?shù)的方法,涉及Python數(shù)值運(yùn)算、排序、判斷等相關(guān)操作技巧,需要的朋友可以參考下2018-05-05如何用python 操作MongoDB數(shù)據(jù)庫(kù)
這篇文章主要介紹了如何用python 操作MongoDB數(shù)據(jù)庫(kù),幫助大家更好的理解和學(xué)習(xí)使用python,感興趣的朋友可以了解下2021-04-04python繪制隨機(jī)網(wǎng)絡(luò)圖形示例
今天小編就為大家分享一篇python繪制隨機(jī)網(wǎng)絡(luò)圖形示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11