8.5 文件与目录——目录操作¶
内容梗概¶
本节课讲解非常实用的目录操作。老师以"批量转码课程录像并上传 B 站"的日常需求引入,介绍用 os 标准库实现目录遍历、创建目录、获取文件信息、删除与重命名等操作。课上通过一个完整示例——输入源目录和目标目录,把源目录下所有文件(含子目录)按体积从大到小排序、加序号重命名并移动到新目录——逐步讲解了 os.listdir 配合递归的遍历写法、os.path.join 的路径拼接、os.path.exists / os.mkdir / os.stat / os.path.basename / os.path.splitext / os.rename 等 API。随后介绍了更高效的 os.walk 遍历方式,最后用 Python 3.4 引入的 pathlib(Path 对象)重写同一示例,展示其简洁性。
知识点详解¶
引入与 os 库概览(约 00:00 - 03:12)¶
- 实际场景:每次课程回放都要遍历录像文件、批量转码成符合 B 站标准的格式再上传——遍历目录是最常见的需求之一。
- Python 提供大量内置**标准库**,最基础的之一是
os(Operating System),负责与操作系统相关的操作。 - 使用前必须
import os。常见功能:目录遍历(两种方式)、创建文件夹、获取文件信息(大小、创建日期等)、删除文件/目录、重命名(即剪切/移动,macOS 下叫 rename)、路径字符串处理。默认参数细节建议直接看文档。
示例功能与效果演示(约 03:12 - 08:00)¶
- 示例:输入要遍历的目录路径和一个新目录名,程序把源目录(含子目录)下所有文件按**体积从大到小**排序,加序号前缀重命名后放进新目录。
- 应用拓展:遍历照片文件夹,对每个文件算**哈希值**,哈希一致即内容重复,可自动找出并删除重复文件——攒了十几年照片人工去重不现实,用 Python 很简单。(提示:作业涉及遍历,但不是排序这个。)
用 listdir + 递归遍历目录(约 08:04 - 19:45)¶
- 自定义函数
walk_dir(path)遍历目录: os.listdir(path):接收目录路径,返回该目录下所有文件和文件夹名组成的**列表**;但它**不会深入子目录**,只列出当前层。- 原始字符串:写 Windows 路径时用
r'...'避免反斜杠转义;注意**原始字符串不能以奇数个反斜杠结尾**(2 个可以,3 个不行),这是 Python 的特点,记住即可。 - 路径拼接:必须用
os.path.join(dir, filename),不要自己用字符串加'\\':- Windows 路径分隔符是反斜杠,Linux 是斜杠,手写拼接的代码在 Linux 下跑不了,Python 程序本应跨平台可移植;
os.path.join自动判断操作系统加分隔符,还能避免用户输入路径末尾已带反斜杠导致的重复分隔符问题。
os.path.isdir(path):判断路径是目录还是文件(返回 True/False)。- 递归逻辑:遇到子目录就递归调用
walk_dir并把结果+=拼接到result列表;遇到文件直接append。最终result里只有文件、没有目录。递归效率不高(之前讲过),但逻辑清晰。 - 用
input获取要遍历的目录和输出目录。 os.path.exists(path):判断路径(文件或目录)是否存在;不存在时用os.mkdir创建目录(存在则跳过不重复创建)。
获取文件大小并排序(约 21:45 - 24:45)¶
os.stat(path):传入路径返回一个对象,内含大小、创建时间、权限等多种信息;取大小属性即可。- 把文件列表转成**字典**:key 是文件路径,value 是文件大小。
- 用之前"数据类型进阶"学过的方法按字典的 value 排序(不记得可回看录像)。
- 老师的写代码习惯:每写一段就
print一下验证前面是否成功,基本不需要专门调试。
重命名并移动(约 24:45 - 29:05)¶
- 初始化编号 1,每处理一个文件编号加 1(最大的文件是 1 号)。
os.path.basename(path):取路径最后一部分(文件名含扩展名,如1.txt),去掉前面所有目录。os.path.splitext(basename):split + extension,把文件名拆成元组('1', '.txt')——前者赋给name、后者赋给ext,以便在中间插入序号。- 新文件名 =
编号_原文件名 + 扩展名,再用os.path.join与新目录拼成完整目标路径,最后os.rename(原路径, 新路径)完成移动(rename 即剪切)。
第二种遍历方式:os.walk(约 29:07 - 33:45)¶
os.walk(path):返回遍历到的每一级目录本身、其子目录列表(dirs)、其文件列表(files),并自动向下层下探,无需手写递归,效率更高。- 演示打印每一轮的
root, dirs, files:第一轮 root 是 backup(2 个子目录、无文件),随后分别以子目录为 root 继续下探,直到没有可遍历内容结束。 - 用法:每轮遍历
files列表,把文件名与当前root用os.path.join拼接后append进结果列表即可。
pathlib:面向对象的路径操作(约 33:45 - 39:43)¶
os.path从 Python 2 时代就有,但它是在**路径字符串**基础上做拼接等操作,没有"路径"这个对象,用起来繁琐。- Python 3.4 引入
pathlib,提供Path对象(类):把路径字符串通过构造函数(类比 C++ 构造函数)转成 Path 对象,之后对路径的所有操作都直接操作这个对象。 - 对应功能:两种遍历、创建文件夹、统计文件信息、删除文件/目录、重命名、拼接路径。拼接路径直接用**斜杠运算符
/**,不用os.path.join。 - 用 pathlib 重写同一示例:
Path(目录).glob(...)遍历目录下所有文件(返回列表,既含文件也含文件夹,需过滤掉文件夹只留文件);Path(新目录).mkdir(exist_ok=True):把"目录是否已存在"的判断隐含到参数里,存在也不报错;- 文件名部分直接用属性:
.stem(不含路径、不含后缀的纯文件名)、.suffix(后缀),不再用basename+splitext; - 用
/运算符拼接输出目录与新文件名,再移动——代码大幅简化。 - 为什么不一上来就教 pathlib:现在仍是新老交替的年代,很多开源项目还在用
os.path,不光要会写代码,还得能看懂别人的代码——这是进阶的基本要求。
示例与演示¶
- 完整示例(os 版):
walk_dir函数用os.listdir+ 递归遍历 backup 目录的所有文件 →os.path.exists/os.mkdir准备输出目录 →os.stat取文件大小构建字典 → 按 value 从大到小排序 → 循环中用basename、splitext组装1_xxx.txt式新文件名 →os.rename移动。运行后 new 目录里文件按大小排序并重新编号。 - 踩坑演示:原始字符串路径末尾多写一个反斜杠导致报错,引出"原始字符串不能以奇数个反斜杠结尾"的规则;缩进多一个空格把自己坑了(Python 缩进严格)。
os.walk演示:逐轮打印root / dirs / files,展示自动下探子目录的过程,并改写成收集所有文件路径的代码。- pathlib 版示例:同一功能用
Path.glob、.stem、.suffix、/拼接、mkdir(exist_ok=True)重写,明显更简洁。
重点与难点¶
os.listdir只列当前层、不进子目录;要遍历整棵树需配合**递归**,或直接用os.walk(效率更高、自动下探)。- 路径拼接永远用
os.path.join(或 pathlib 的/),不要手写'\\':跨平台分隔符不同、还可能重复分隔符。 - Windows 路径用原始字符串
r'...'防转义;原始字符串不能以奇数个反斜杠结尾。 os.rename同时承担重命名与移动(剪切)功能;os.stat返回的对象含大小、时间、权限等多种信息。- pathlib(3.4+)是当前**最推荐**的写法,但
os.path在老项目中仍大量存在,两种都要看得懂。 - 递归遍历返回结果里只有文件没有目录——目录被"展开"处理掉了,这个设计要想清楚。
关联内容¶
- 用到大量前置知识:函数与递归(讲函数时学过)、字典及其按 value 排序(数据类型进阶)、序列与列表操作、字符串的原始字符串记法(讲字符串时)。
- 标准库
os的使用为第 9 章系统介绍 Python 标准库/第三方库预热;老师明确说"这涉及到下节课的一部分内容"。 - 遍历目录 + 读文件头是 8.6 节作业"猫鼠游戏"的直接技术基础;去重文件的哈希思路预告了后续"更多酷的内容"。
- 遍历 + 排序 + 重命名的完整流程是 Python 作为"脚本语言"处理日常事务(整理照片、批量转码)的典型场景。