翼度科技»论坛 编程开发 python 查看内容

扫叶林风后,拾薪山雨前

4

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12
作者:袁首京  原创文章,转载时请保留此声明,并给出原文连接。
草堂南涧边,有客啸云烟。
扫叶林风后,拾薪山雨前。
野桥通竹径,流水入芝田。
琴月相亲夜,更深恋不眠。
话说周世宗显德年间,有位老先生,性情疏野,不以荣宦为意。一生遇见了很多人、经历了许多事。可惜这些事我一件也不知道、这些人我一个也不晓得。所以以下内容除了这个开头,通篇与这首诗、这个人都毫无关系。
只不过是前天随意翻了一下我的移动硬盘,存的东西那叫一个乱。很多东西在不同的目录或者是相似的目录多次出现,也不知道哪个是新的、哪个是老的,哪个是有用的、哪个是没用的,动也不敢动、删也不敢删,越看越闹心、越不顺眼。是时候该整理一下了。

但是真要动手,就发现这个事儿并不有趣。单单是比较两个文件,就很浪费时间和精力。难道要一个个打开来看?很明显就不现实。我要有这么勤快,硬盘也不会乱到这种程度。只好写一段程序来处理了。
用什么写呢?这种事儿,Windows 上bat或powershell、Linux 上 shell 可能就很合适,只不过这些我都不熟悉。我用的是 python,几十行代码就基本可以使用了。最终效果如下:

你可能注意到,最终生成的是一个命令行程序 file_organizer.exe(文末附下载链接)。回头有空也可以写个图形界面的,不过一回头通常就不知道回到啥时候了,管它呢,总之回头再说。眼下先把已经写过的这几十行代码交待一下。
需求分析

简单的说,文件整理这个事儿可以分解为分类清理两个过程。大概需要回答以下问题:

  • 要从哪个文件夹里挑选文件?
  • 挑选哪种类型的文件,文档、表格、图片还是别的?
  • 挑出的文件放在哪个文件夹?
  • 挑出的文件放入新文件夹时,如果发现新文件夹中已经有同名文件了,该怎么处理?
  • 文件放到新文件夹后,原来的文件夹中还保留不保留?
接口定义

问题弄明白,事儿就好干了。根据上述五个问题,我们可以给出如下的函数定义:
  1. def organize(src: str, exts: str, dst: str, copy: bool = True, strategy: str):
  2.     """
  3.     :param src:str 源路径
  4.     :param exts:str 扩展名
  5.     :param dst:str 目的路径
  6.     :param copy:bool 复制文件还是移动文件到目的路径
  7.     :param strategy:str 重名处理策略
  8.     """
  9.     pass
复制代码
上述定义中,源路径和目的路径都是目录。目录可能有很多层级,我们需要遍历其中的每一个文件,如果发现文件的扩展名,是需要处理的类型,则按策略对其采取迁移到目的路径的操作。这个操作会在遍历的过程中反复执行,因此可以针对它再定义如下函数:
  1. def deal(src: Path, dst: Path, copy: bool = True, strategy: str = "both"):
  2.     """
  3.     :param src:Path 源路径
  4.     :param dst:Path 目的路径
  5.     :param copy:bool 复制文件还是移动文件到目的路径
  6.     :param strategy:str 重名处理策略
  7.     """
  8.     pass
复制代码
其它还有不少操作,其中之一是假如遇到同名文件,如何判定它们是一样的?方法有很多,比如对比它们的 md5sum 结果等等。Python 标准库中有个 filecmp 就是处理这件事儿的,所以我们不用计算 md5sum 了。除此之外似乎没什么需要特别关注的点了。
编码实现

事儿不大,不啰嗦了。以下就是核心代码了:
  1. import shutil
  2. from loguru import logger
  3. from os import walk, listdir
  4. from pathlib import Path
  5. from filecmp import cmp
  6. def rename(file_name: str) -> str:
  7.     idx = file_name.index(".")
  8.     return file_name[:idx] + "_1" + file_name[idx:]
  9. def deal(src: Path, dst: Path, copy: bool = True, strategy: str = "both"):
  10.     if not dst.exists():
  11.         shutil.copy2(src, dst)
  12.         logger.info("迁移原文件到 {}", dst)
  13.     elif cmp(src, dst):
  14.         logger.info("无需迁移文件 {}", dst)
  15.     elif strategy == "later" and src.stat().st_mtime > dst.stat().st_mtime:
  16.         shutil.copy2(src, dst)
  17.         logger.info("迁移新文件到 {}", dst)
  18.     elif strategy == "bigger" and src.stat().st_size > dst.stat().st_size:
  19.         shutil.copy2(src, dst)
  20.         logger.info("迁移大文件到 {}", dst)
  21.     else:
  22.         dst = dst.parent / Path(rename(dst.name))
  23.         shutil.copy2(src, dst)
  24.         logger.info("重命名文件到 {}", dst)
  25.     if not copy:
  26.         src.unlink()
  27. def organize(src: str, exts: str, dst: str, copy: bool = True, strategy: str = "both"):
  28.     if not exts or len(exts) < 1:
  29.         raise ValueError('"exts" is invalid')
  30.     lc_exts = [e.lower() for e in exts.split()]
  31.     src_path = Path(src)
  32.     dst_path = Path(dst)
  33.     if not src_path.exists() or not src_path.is_dir():
  34.         raise ValueError('"src" is invalid')
  35.     if not dst_path.exists():
  36.         dst_path.mkdir(parents=True, exist_ok=True)
  37.     for root, _, files in walk(src):
  38.         for name in files:
  39.             file = Path(root) / Path(name)
  40.             if file.suffix.lower() not in lc_exts:
  41.                 continue
  42.             target = dst_path / Path(name)
  43.             deal(file, target, copy, strategy)
  44.     if not copy and len(listdir(src_path)) < 1:
  45.         src_path.rmdir()
复制代码
除此之外,就是些辅助代码了,例如命令行帮助等等。此处不再罗列,我放在了 Github 上,需要的话可以去看。https://github.com/yuanshoujing/file_organizer
下载

最后,如果你需要的话,可以点击如下链接下载打包的命令行程序:
此程序只能在 win10 以上系统中运行,并且没有经过严肃测试,请谨慎使用,出了问题概不负责。
  作者:袁首京     原创文章,转载时请保留此声明,并给出原文连接。
来源:https://www.cnblogs.com/rockety/p/17285423.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具