作者:袁首京
原創文章,轉載時請保留此宣告,并給出原文連接,
草堂南澗邊,有客嘯云煙,
掃葉林風后,拾薪山雨前,
野橋通竹徑,流水入芝田,
琴月相親夜,更深戀不眠,
話說周世宗顯德年間,有位老先生,性情疏野,不以榮宦為意,一生遇見了很多人、經歷了許多事,可惜這些事我一件也不知道、這些人我一個也不曉得,所以以下內容除了這個開頭,通篇與這首詩、這個人都毫無關系,
只不過是前天隨意翻了一下我的移動硬碟,存的東西那叫一個亂,很多東西在不同的目錄或者是相似的目錄多次出現,也不知道哪個是新的、哪個是老的,哪個是有用的、哪個是沒用的,動也不敢動、刪也不敢刪,越看越鬧心、越不順眼,是時候該整理一下了,

但是真要動手,就發現這個事兒并不有趣,單單是比較兩個檔案,就很浪費時間和精力,難道要一個個打開來看?很明顯就不現實,我要有這么勤快,硬碟也不會亂到這種程度,只好寫一段程式來處理了,
用什么寫呢?這種事兒,Windows 上bat或powershell、Linux 上 shell 可能就很合適,只不過這些我都不熟悉,我用的是 python,幾十行代碼就基本可以使用了,最終效果如下:

你可能注意到,最終生成的是一個命令列程式 file_organizer.exe(文末附下載鏈接),回頭有空也可以寫個圖形界面的,不過一回頭通常就不知道回到啥時候了,管它呢,總之回頭再說,眼下先把已經寫過的這幾十行代碼交待一下,
需求分析
簡單的說,檔案整理這個事兒可以分解為分類和清理兩個程序,大概需要回答以下問題:
- 要從哪個檔案夾里挑選檔案?
- 挑選哪種型別的檔案,檔案、表格、圖片還是別的?
- 挑出的檔案放在哪個檔案夾?
- 挑出的檔案放入新檔案夾時,如果發現新檔案夾中已經有同名檔案了,該怎么處理?
- 檔案放到新檔案夾后,原來的檔案夾中還保留不保留?
介面定義
問題弄明白,事兒就好干了,根據上述五個問題,我們可以給出如下的函式定義:
def organize(src: str, exts: str, dst: str, copy: bool = True, strategy: str):
"""
:param src:str 源路徑
:param exts:str 擴展名
:param dst:str 目的路徑
:param copy:bool 復制檔案還是移動檔案到目的路徑
:param strategy:str 重名處理策略
"""
pass
上述定義中,源路徑和目的路徑都是目錄,目錄可能有很多層級,我們需要遍歷其中的每一個檔案,如果發現檔案的擴展名,是需要處理的型別,則按策略對其采取遷移到目的路徑的操作,這個操作會在遍歷的程序中反復執行,因此可以針對它再定義如下函式:
def deal(src: Path, dst: Path, copy: bool = True, strategy: str = "both"):
"""
:param src:Path 源路徑
:param dst:Path 目的路徑
:param copy:bool 復制檔案還是移動檔案到目的路徑
:param strategy:str 重名處理策略
"""
pass
其它還有不少操作,其中之一是假如遇到同名檔案,如何判定它們是一樣的?方法有很多,比如對比它們的 md5sum 結果等等,Python 標準庫中有個 filecmp 就是處理這件事兒的,所以我們不用計算 md5sum 了,除此之外似乎沒什么需要特別關注的點了,
編碼實作
事兒不大,不啰嗦了,以下就是核心代碼了:
import shutil
from loguru import logger
from os import walk, listdir
from pathlib import Path
from filecmp import cmp
def rename(file_name: str) -> str:
idx = file_name.index(".")
return file_name[:idx] + "_1" + file_name[idx:]
def deal(src: Path, dst: Path, copy: bool = True, strategy: str = "both"):
if not dst.exists():
shutil.copy2(src, dst)
logger.info("遷移原檔案到 {}", dst)
elif cmp(src, dst):
logger.info("無需遷移檔案 {}", dst)
elif strategy == "later" and src.stat().st_mtime > dst.stat().st_mtime:
shutil.copy2(src, dst)
logger.info("遷移新檔案到 {}", dst)
elif strategy == "bigger" and src.stat().st_size > dst.stat().st_size:
shutil.copy2(src, dst)
logger.info("遷移大檔案到 {}", dst)
else:
dst = dst.parent / Path(rename(dst.name))
shutil.copy2(src, dst)
logger.info("重命名檔案到 {}", dst)
if not copy:
src.unlink()
def organize(src: str, exts: str, dst: str, copy: bool = True, strategy: str = "both"):
if not exts or len(exts) < 1:
raise ValueError('"exts" is invalid')
lc_exts = [e.lower() for e in exts.split()]
src_path = Path(src)
dst_path = Path(dst)
if not src_path.exists() or not src_path.is_dir():
raise ValueError('"src" is invalid')
if not dst_path.exists():
dst_path.mkdir(parents=True, exist_ok=True)
for root, _, files in walk(src):
for name in files:
file = Path(root) / Path(name)
if file.suffix.lower() not in lc_exts:
continue
target = dst_path / Path(name)
deal(file, target, copy, strategy)
if not copy and len(listdir(src_path)) < 1:
src_path.rmdir()
除此之外,就是些輔助代碼了,例如命令列幫助等等,此處不再羅列,我放在了 Github 上,需要的話可以去看,https://github.com/yuanshoujing/file_organizer
下載
最后,如果你需要的話,可以點擊如下鏈接下載打包的命令列程式:
- file_organizer.exe
此程式只能在 win10 以上系統中運行,并且沒有經過嚴肅測驗,請謹慎使用,出了問題概不負責,
作者:袁首京原創文章,轉載時請保留此宣告,并給出原文連接,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/549122.html
標籤:其他
