4、文件与文件夹操作:os模块与pathlib模块

说到文件操作,这可是RPA的看家本领。

你想想看,一个自动化流程里,十有八九都要跟文件打交道。我刚开始写RPA脚本时,最头疼的就是文件路径处理——Windows用反斜杠,Linux用正斜杠,稍不注意就报错。后来用熟了pathlib,才觉得世界清净了。

4.1 os模块 vs pathlib模块:我该用哪个?

Python里有两个主流方案:老牌的os模块,和Python 3.4引入的pathlib

我个人习惯是这样分的:

  • 简单操作(比如判断文件是否存在、获取当前目录)——用os就够了
  • 复杂路径处理(拼接、拆分、批量操作)——用pathlib,代码更优雅

举个例子你就明白了:

# os模块的老写法
import os
folder = os.path.join("C:\\", "Users", "admin", "Desktop")
files = os.listdir(folder)

# pathlib的新写法
from pathlib import Path
folder = Path("C:/Users/admin/Desktop")
files = list(folder.iterdir())

看出来没?pathlib/运算符拼接路径,直观多了。我在项目中遇到过好几次因为os.path.join参数顺序搞错导致的bug,换成pathlib后再也没犯过。

我的建议:新项目直接用pathlib。除非你要兼容Python 2的老代码,否则别纠结。

4.2 核心操作:创建、删除、重命名

这些操作其实就几个函数,但细节挺多。我一个个说。

4.2.1 创建文件夹

from pathlib import Path

# 创建单层目录
Path("my_folder").mkdir(exist_ok=True)

# 创建多层目录(比如 a/b/c)
Path("a/b/c").mkdir(parents=True, exist_ok=True)

exist_ok=True这个参数很实用。如果不加,文件夹已存在时会报错。我刚开始写代码时经常忘了加,结果脚本跑第二次就崩了。

4.2.2 删除文件或文件夹

import os
from pathlib import Path

# 删除文件
os.remove("old_file.txt")
# 或者
Path("old_file.txt").unlink()

# 删除空文件夹
os.rmdir("empty_folder")
# 或者
Path("empty_folder").rmdir()

# 删除非空文件夹(慎用!)
import shutil
shutil.rmtree("non_empty_folder")
我曾经踩过的坑:shutil.rmtree会直接删除整个目录树,没有回收站!有一次我在测试环境写了个脚本,路径写错了,结果把项目文件夹删了...从那以后,我每次用rmtree前都会先打印路径确认一遍。

4.2.3 重命名与移动

from pathlib import Path

# 重命名
Path("old_name.txt").rename("new_name.txt")

# 移动文件(其实就是重命名路径)
Path("source/file.txt").rename("target/file.txt")

嗯,这里要注意:rename既可以重命名也可以移动。说白了,它就是改了文件的路径名。

4.3 批量操作:重命名、移动、复制

这才是RPA的用武之地。假设你有一堆文件,要批量改名字、分类移动,手点得累死,但Python几行代码搞定。

4.3.1 批量重命名

from pathlib import Path

folder = Path("./downloads")
for i, file in enumerate(folder.iterdir()):
    if file.is_file():
        new_name = f"report_{i+1}{file.suffix}"
        file.rename(folder / new_name)

这个例子把所有文件重命名为report_1.pdfreport_2.docx这样的格式。你想想看,如果每天有几十个下载文件要整理,这段代码能省多少时间。

4.3.2 批量移动(按扩展名分类)

from pathlib import Path
import shutil

source = Path("./downloads")
targets = {
    ".pdf": Path("./PDFs"),
    ".docx": Path("./Word"),
    ".xlsx": Path("./Excel"),
}

for file in source.iterdir():
    if file.is_file():
        ext = file.suffix.lower()
        if ext in targets:
            target_folder = targets[ext]
            target_folder.mkdir(exist_ok=True)
            shutil.move(str(file), str(target_folder / file.name))

这段代码我经常用在整理客户发来的文件上。PDF归PDF,Word归Word,一目了然。

4.3.3 批量复制(带进度感)

from pathlib import Path
import shutil

source = Path("./source_folder")
dest = Path("./backup_folder")
dest.mkdir(exist_ok=True)

for file in source.iterdir():
    if file.is_file():
        shutil.copy2(str(file), str(dest / file.name))
        print(f"已复制: {file.name}")

shutil.copy2shutil.copy好一点——它会保留文件的元数据(比如修改时间)。我在做备份脚本时都用它。

4.4 实战:整理桌面文件

好了,理论说完了,咱们来点实际的。

我自己的桌面经常乱成一团——截图、PDF、压缩包、临时脚本...每次找文件都头疼。后来我写了个小脚本,一键整理。

from pathlib import Path
import shutil

def organize_desktop():
    desktop = Path.home() / "Desktop"
    
    # 定义分类规则
    rules = {
        "图片": [".png", ".jpg", ".jpeg", ".gif", ".bmp"],
        "文档": [".pdf", ".docx", ".txt", ".xlsx", ".pptx"],
        "压缩包": [".zip", ".rar", ".7z", ".tar", ".gz"],
        "脚本": [".py", ".js", ".bat", ".sh"],
        "其他": []  # 兜底
    }
    
    for file in desktop.iterdir():
        if file.is_file() and not file.name.startswith("."):
            moved = False
            for folder_name, extensions in rules.items():
                if file.suffix.lower() in extensions:
                    target = desktop / folder_name
                    target.mkdir(exist_ok=True)
                    shutil.move(str(file), str(target / file.name))
                    moved = True
                    print(f"移动: {file.name} -> {folder_name}")
                    break
            
            # 没匹配到的归入"其他"
            if not moved:
                other = desktop / "其他"
                other.mkdir(exist_ok=True)
                shutil.move(str(file), str(other / file.name))
                print(f"移动: {file.name} -> 其他")

if __name__ == "__main__":
    organize_desktop()

这段代码的逻辑很简单:

  1. 遍历桌面所有文件
  2. 根据扩展名判断属于哪一类
  3. 移动到对应的分类文件夹
  4. 没匹配到的统一放"其他"
避坑指南:我曾经把脚本跑在桌面上,结果把自己正在编辑的代码文件也移动了...所以建议加个白名单,或者只处理特定前缀的文件。安全第一。

4.5 总结一下

文件操作这块,说白了就三件事:

  • 路径处理——用pathlib,别自己拼字符串
  • 增删改查——记住mkdirrenameunlinkrmdir
  • 批量操作——配合for循环和shutil模块

你想想看,这些技能组合起来,能做出多少自动化工具?文件备份、日志归档、下载整理...RPA的价值就在这里——把重复劳动交给机器,你去做更有意义的事。

下一章咱们聊聊更高级的:用watchdog模块监控文件变化,实现实时触发。嗯,那个更有意思。