上周五下午5点,领导甩过来一个文件夹:「这3000个PDF发票,明天前帮我转成Excel。」
我差点原地去世。
手动转?按每份2分钟算,不吃不喝干10个小时。用Python?5行代码,3分钟跑完。
os模块:文件操作的瑞士军刀
Python处理文件,绕不开os模块。它不花哨,但实打实能干活。
路径拼接、目录遍历、文件重命名——这些脏活累活,os模块全包了。
路径操作:别再用字符串拼接了
新手最爱犯的错:用 + 号拼路径。Windows用反斜杠,Mac用正斜杠,代码一换环境就炸。
os.path.join 自动处理分隔符,跨平台不会出错:
import os# 错误示范:字符串拼接path = "C:" + "\\Users" + "\\test" + "\\file.txt"# 正确做法:os.path.joinpath = os.path.join("C:", "Users", "test", "file.txt")print(path) # C:Users\test\file.txt(Windows自动用反斜杠)
其他常用路径函数:
# 判断路径是否存在os.path.exists("/home/test/data") # True/False# 获取文件扩展名os.path.splitext("report.pdf") # ('report', '.pdf')# 获取文件名和目录os.path.basename("/home/test/report.pdf") # 'report.pdf'os.path.dirname("/home/test/report.pdf") # '/home/test'# 获取文件大小(字节)os.path.getsize("report.pdf") # 102400
目录操作:遍历文件夹的三种姿势
拿到一个文件夹,第一件事就是看里面有什么。os模块提供了三个函数,各有适用场景。
os.listdir —— 只看一层:
# 获取目录下所有文件名(不递归)files = os.listdir("/data/invoices")print(files) # ['inv001.pdf', 'inv002.pdf', 'inv003.xlsx', ...]
os.walk —— 递归遍历,拿到完整路径:
# os.walk返回(目录路径, 子目录列表, 文件列表)的元组for root, dirs, files in os.walk("/data/invoices"): for file in files: full_path = os.path.join(root, file) print(full_path)# 输出:# /data/invoices/inv001.pdf# /data/invoices/2024/inv002.pdf# /data/invoices/2024/inv003.pdf
os.makedirs —— 一次性创建多层目录:
# 递归创建目录,exist_ok=True表示目录存在也不报错os.makedirs("/data/output/2024/invoices", exist_ok=True)
文件操作:重命名、删除、移动
文件操作三件套:改名、删掉、看信息。
# 重命名文件os.rename("old_name.txt", "new_name.txt")# 删除文件(不存在会报错,先判断)if os.path.exists("temp.txt"): os.remove("temp.txt")# 获取文件信息(大小、修改时间等)stat = os.stat("report.pdf")print(f"大小: {stat.st_size} 字节")print(f"修改时间: {stat.st_mtime}")
批量处理实战:从遍历到筛选
光说不练假把式。来个真实场景:把/data/invoices目录下所有PDF文件的名称,从"发票_001.pdf"改成"INV_001.pdf"。
import os# 设定目录folder = "/data/invoices"# 遍历所有文件for filename in os.listdir(folder): # 筛选:只要PDF,且以"发票_"开头 if filename.endswith(".pdf") and filename.startswith("发票_"): # 构造新文件名 new_name = filename.replace("发票_", "INV_") # 拼接完整路径 old_path = os.path.join(folder, filename) new_path = os.path.join(folder, new_name) # 重命名 os.rename(old_path, new_path) print(f"重命名: {filename} -> {new_name}")print("批量重命名完成!")
这段代码干了三件事:遍历 → 筛选 → 重命名。核心逻辑就8行,但能处理上万个文件。
案例:批量PDF转Excel/文本
回到开头的需求:3000个PDF发票,转成Excel。
需要用到额外的库:pdfplumber(提取PDF表格数据)和 openpyxl(写Excel)。
先装依赖:
pip install pdfplumber openpyxl
完整代码:
import osimport pdfplumberfrom openpyxl import Workbookdef pdf_to_excel(pdf_path, excel_path): """把一个PDF里的表格提取到Excel""" wb = Workbook() ws = wb.active with pdfplumber.open(pdf_path) as pdf: for page in pdf.pages: tables = page.extract_tables() for table in tables: for row in table: ws.append(row) wb.save(excel_path)# 批量处理source_dir = "/data/invoices"output_dir = "/data/invoices_excel"os.makedirs(output_dir, exist_ok=True)pdf_count = 0for filename in os.listdir(source_dir): if filename.endswith(".pdf"): pdf_path = os.path.join(source_dir, filename) excel_name = filename.replace(".pdf", ".xlsx") excel_path = os.path.join(output_dir, excel_name) pdf_to_excel(pdf_path, excel_path) pdf_count += 1 print(f"[{pdf_count}] 已转换: {filename}")print(f"\n全部完成!共处理 {pdf_count} 个文件")
跑完之后,output文件夹里整整齐齐躺着3000个xlsx文件。整个过程不到3分钟。
踩坑记录:这些坑我替你踩过了
坑1:路径分隔符
Windows用 \\,Mac/Linux用 /。直接拼字符串必翻车。
解决方案:永远用os.path.join,不要手动拼。
坑2:中文文件名乱码
Windows下os.listdir()返回的中文文件名可能是乱码,因为系统默认编码是gbk。
解决方案:
import sysimport os# Windows下设置编码if sys.platform == 'win32': # 方法1:设置环境变量 os.environ['PYTHONIOENCODING'] = 'utf-8' # 方法2:对文件名进行编码转换 for filename in os.listdir('.'): if isinstance(filename, bytes): filename = filename.decode('utf-8')
坑3:PermissionError
正在读写文件时,另一个程序(比如Excel)占用了文件,直接报错。
解决方案:加try-except,跳过出错的文件继续处理。
for filename in os.listdir(source_dir): try: # 你的处理逻辑 process_file(filename) except PermissionError: print(f"跳过被占用的文件: {filename}") continue
彩蛋:pathlib,更Pythonic的写法
Python 3.4引入了pathlib模块,用面向对象的方式处理路径,比os.path更优雅。
from pathlib import Path# 创建路径对象folder = Path("/data/invoices")# 遍历所有PDF(比os.listdir更直观)for pdf_file in folder.glob("*.pdf"): print(pdf_file.name) # 文件名 print(pdf_file.suffix) # 扩展名:.pdf print(pdf_file.stem) # 不带扩展名:report # 重命名 new_name = pdf_file.stem.replace("发票", "INV") + ".pdf" pdf_file.rename(folder / new_name)
pathlib的路径用 / 拼接,代码更清晰。新项目建议优先用pathlib,老代码维护用os也完全没问题。
写在最后
文件批量处理是Python最实用的技能之一。掌握os模块,能帮你省下大量重复劳动。
记住三个原则:
留个问题: 你用Python批量处理文件时,遇到过最坑的问题是什么?评论区聊聊,点赞最高的我下期专门写解决方案。