👋 大家好,欢迎来到我的技术博客!
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕Python进阶这个话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!
文章目录
- 🐍 Python进阶:os模块遍历目录下的所有文件 🌳
- 📁 什么是 os 模块?
- 🚶♂️ 基础:使用 os.listdir() 遍历目录
- 🔍 递归遍历:os.walk() —— 真正的“全遍历”工具
- ✅ 示例代码:完整递归遍历
- 🧩 输出示例(简化):
- 🌐 os.walk() 的内部机制:一个动态图解
- ⚠️ 处理常见异常:权限与路径错误
- ✅ 安全遍历:添加异常处理
- 🔎 高级技巧:按条件筛选文件
- ✅ 示例:只列出 `.txt` 和 `.md` 文件
- 🗂️ 排除特定目录或文件
- ✅ 示例:排除隐藏目录和缓存目录
- 🕵️♀️ 获取文件详细信息:mtime、ctime、size
- ✅ 示例:获取文件详细信息
- 🔄 实战项目:批量重命名文件
- ✅ 示例:自动重命名图片文件
- 🛠️ 使用 pathlib 替代 os?—— 一个现代建议
- ✅ 对比:os vs pathlib
- 1. 传统 os 写法:
- 2. 现代 pathlib 写法:
- 🧪 单元测试:确保你的遍历逻辑正确
- 📊 性能对比:os.walk() vs pathlib.rglob()
- 🧩 实用技巧总结
- 🌐 附加资源 & 学习建议
- 🎯 结语:掌握 os.walk(),就是掌握自动化核心
🐍 Python进阶:os模块遍历目录下的所有文件 🌳
在日常的编程工作中,我们经常需要处理文件和目录的操作。无论是数据清洗、日志分析、批量重命名,还是自动化脚本编写,遍历目录中的所有文件都是一个非常基础但又极其重要的技能。而os模块作为 Python 标准库中与操作系统交互的核心模块,提供了强大的功能来完成这项任务。
今天,我们就来深入探讨如何使用os模块高效、安全地遍历目录下的所有文件,包括子目录、隐藏文件、权限控制等高级场景,并通过实际代码示例带你从入门到精通。✨
📁 什么是 os 模块?
os模块是 Python 的标准库之一,它提供了一种方式来使用操作系统的功能,如文件和目录操作、环境变量管理、进程管理等。它在不同平台上(Windows、Linux、macOS)都能保持一致的行为,是跨平台开发的理想选择。
💡 提示:
os模块不依赖外部库,开箱即用,非常适合做系统级操作。
🚶♂️ 基础:使用 os.listdir() 遍历目录
最简单的遍历方式是使用os.listdir()函数。它返回指定目录下所有文件和子目录的名称列表。
importos# 指定要遍历的目录路径directory="/path/to/your/folder"# 获取目录内容files_and_dirs=os.listdir(directory)print("目录内容:")foriteminfiles_and_dirs:print(f"📁{item}")📌注意:
os.listdir()只列出当前目录的内容,不会递归进入子目录。- 它返回的是字符串列表,包含文件名和文件夹名。
- 如果路径不存在或没有访问权限,会抛出
FileNotFoundError或PermissionError。
🔍 递归遍历:os.walk() —— 真正的“全遍历”工具
如果你需要遍历一个目录及其所有子目录中的文件,os.walk()是你的首选。它是一个生成器函数,逐层返回(dirpath, dirnames, filenames)三元组。
✅ 示例代码:完整递归遍历
importosdeftraverse_directory(root_dir):print(f"🔍 正在遍历目录:{root_dir}")fordirpath,dirnames,filenamesinos.walk(root_dir):# 打印当前目录路径print(f"📂 当前目录:{dirpath}")# 打印所有文件forfilenameinfilenames:file_path=os.path.join(dirpath,filename)print(f"📄 文件:{file_path}")# 打印所有子目录(可选)fordirnameindirnames:dir_full_path=os.path.join(dirpath,dirname)print(f"📁 子目录:{dir_full_path}")# 调用函数traverse_directory("/Users/yourname/Documents")🧩 输出示例(简化):
🔍 正在遍历目录: /Users/yourname/Documents 📂 当前目录: /Users/yourname/Documents 📄 文件: /Users/yourname/Documents/report.pdf 📄 文件: /Users/yourname/Documents/config.json 📁 子目录: /Users/yourname/Documents/backup 📂 当前目录: /Users/yourname/Documents/backup 📄 文件: /Users/yourname/Documents/backup/old_data.zip🌐 os.walk() 的内部机制:一个动态图解
让我们用 Mermaid 画一张流程图,展示os.walk()如何递归遍历目录结构。
✅ 这个图展示了os.walk()的递归逻辑:先深入到底层,再逐步回溯处理每一层的文件。
⚠️ 处理常见异常:权限与路径错误
在真实环境中,你可能遇到以下问题:
- 目录不存在
- 无读取权限
- 文件名包含特殊字符(如中文、符号)
✅ 安全遍历:添加异常处理
importosdefsafe_traverse(root_dir):try:ifnotos.path.exists(root_dir):print("❌ 路径不存在!")returnifnotos.access(root_dir,os.R_OK):print("❌ 没有读取权限!")returnprint(f"✅ 开始安全遍历:{root_dir}")fordirpath,dirnames,filenamesinos.walk(root_dir):print(f"📂 目录:{dirpath}")forfilenameinfilenames:file_path=os.path.join(dirpath,filename)try:# 尝试获取文件大小(测试是否可读)size=os.path.getsize(file_path)print(f"📄{filename}(大小:{size}bytes)")exceptOSErrorase:print(f"⚠️ 无法读取文件:{file_path}| 错误:{e}")exceptExceptionase:print(f"💥 发生未知错误:{e}")# 调用safe_traverse("/Users/yourname/Documents")💡关键点:
- 使用
os.path.exists()判断路径是否存在。 - 使用
os.access(path, os.R_OK)检查读权限。 - 在
os.walk()内部对每个文件加try-except,避免因单个文件失败导致整个遍历中断。
🔎 高级技巧:按条件筛选文件
很多时候我们不需要遍历所有文件,而是只关心特定类型的文件,比如.py、.log、.jpg等。
✅ 示例:只列出.txt和.md文件
importosdeffilter_files_by_extension(root_dir,extensions):matched_files=[]fordirpath,_,filenamesinos.walk(root_dir):forfilenameinfilenames:ifany(filename.lower().endswith(ext.lower())forextinextensions):full_path=os.path.join(dirpath,filename)matched_files.append(full_path)print(f"✅ 匹配:{full_path}")print(f"\n📊 共找到{len(matched_files)}个匹配文件。")returnmatched_files# 使用txt_md_files=filter_files_by_extension(root_dir="/Users/yourname/Documents",extensions=['.txt','.md'])🗂️ 排除特定目录或文件
有时我们需要跳过某些目录,比如.git、__pycache__、node_modules等。
✅ 示例:排除隐藏目录和缓存目录
importosdeftraverse_with_exclusions(root_dir,exclude_dirs=None):ifexclude_dirsisNone:exclude_dirs={'.git','__pycache__','node_modules','.venv'}print(f"🚀 开始遍历,排除:{exclude_dirs}")fordirpath,dirnames,filenamesinos.walk(root_dir):# 动态过滤掉不想遍历的目录dirnames[:]=[dfordindirnamesifdnotinexclude_dirs]print(f"📂 当前目录:{dirpath}")forfilenameinfilenames:print(f"📄{filename}")# 调用traverse_with_exclusions("/Users/yourname/project")✅
dirnames[:] = [...]是关键技巧——它修改了os.walk()的内部目录列表,实现“跳过”某些子目录。
🕵️♀️ 获取文件详细信息:mtime、ctime、size
除了文件名,我们还常需要知道文件的创建时间、修改时间、大小等元数据。
✅ 示例:获取文件详细信息
importosfromdatetimeimportdatetimedefget_file_info(root_dir):print("📊 文件详细信息汇总:")print("-"*60)fordirpath,_,filenamesinos.walk(root_dir):forfilenameinfilenames:file_path=os.path.join(dirpath,filename)try:stat=os.stat(file_path)# 转换时间戳为可读格式mtime=datetime.fromtimestamp(stat.st_mtime).strftime('%Y-%m-%d %H:%M:%S')ctime=datetime.fromtimestamp(stat.st_ctime).strftime('%Y-%m-%d %H:%M:%S')size=stat.st_sizeprint(f"📄{filename}")print(f" 🕒 修改时间:{mtime}")print(f" 🕒 创建时间:{ctime}")print(f" 📏 大小:{size}bytes")print(f" 📍 路径:{file_path}")print("-"*40)exceptExceptionase:print(f"⚠️ 无法获取信息:{file_path}| 错误:{e}")get_file_info("/Users/yourname/Documents")📌说明:
os.stat()返回文件状态对象。st_mtime: 最后修改时间(modification time)st_ctime: 创建时间(creation time,部分系统支持)st_size: 文件大小(字节)
🔄 实战项目:批量重命名文件
假设你要将某个目录下所有的.jpg文件重命名为img_001.jpg,img_002.jpg…
✅ 示例:自动重命名图片文件
importosdefrename_images_in_folder(folder_path,prefix="img"):count=1renamed=0fordirpath,_,filenamesinos.walk(folder_path):forfilenameinfilenames:iffilename.lower().endswith(('.jpg','.jpeg','.png','.bmp')):old_path=os.path.join(dirpath,filename)new_filename=f"{prefix}_{count:03d}{os.path.splitext(filename)[1]}"new_path=os.path.join(dirpath,new_filename)try:os.rename(old_path,new_path)print(f"✅ 重命名:{filename}→{new_filename}")renamed+=1count+=1exceptOSErrorase:print(f"❌ 重命名失败:{old_path}→{new_path}| 错误:{e}")print(f"🎉 完成!共重命名{renamed}个文件。")# 调用rename_images_in_folder("/Users/yourname/Pictures")🎯 这个脚本可以用于整理照片、清理命名混乱的文件夹。
🛠️ 使用 pathlib 替代 os?—— 一个现代建议
虽然os模块功能强大,但 Python 3.4+ 推荐使用pathlib模块,它更面向对象,语法更清晰。
✅ 对比:os vs pathlib
1. 传统 os 写法:
importosfordirpath,_,filenamesinos.walk("/home/user/docs"):forfinfilenames:path=os.path.join(dirpath,f)iff.endswith(".log"):print(path)2. 现代 pathlib 写法:
frompathlibimportPath root=Path("/home/user/docs")forfile_pathinroot.rglob("*.log"):print(file_path)🌟
rglob()是glob()的递归版本,相当于os.walk()+glob组合。
🔗 Python 官方文档 - pathlib
🔗 Real Python - pathlib 教程
🧪 单元测试:确保你的遍历逻辑正确
为了保证代码健壮,我们可以写一个简单的测试用例。
importunittestimportosimporttempfileclassTestDirectoryTraversal(unittest.TestCase):defsetUp(self):# 创建临时目录结构self.temp_dir=tempfile.mkdtemp()sub_dir=os.path.join(self.temp_dir,"subfolder")os.makedirs(sub_dir)withopen(os.path.join(self.temp_dir,"test1.txt"),"w")asf:f.write("hello")withopen(os.path.join(sub_dir,"test2.py"),"w")asf:f.write("print('hi')")deftearDown(self):# 清理临时目录os.removedirs(self.temp_dir)deftest_traverse_with_filter(self):frompathlibimportPath matches=list(Path(self.temp_dir).rglob("*.txt"))self.assertEqual(len(matches),1)self.assertIn("test1.txt",str(matches[0]))if__name__=="__main__":unittest.main()📊 性能对比:os.walk() vs pathlib.rglob()
| 方法 | 优点 | 缺点 |
|---|---|---|
os.walk() | 传统、兼容性好、灵活 | 代码略长,需手动拼接路径 |
pathlib.rglob() | 语法简洁,可读性强 | 需要 Python 3.4+ |
✅ 推荐:新项目优先使用
pathlib,旧项目可保留os.walk()。
🧩 实用技巧总结
| 技巧 | 说明 |
|---|---|
os.path.join() | 安全拼接路径,自动适配 OS 分隔符 |
os.path.exists() | 检查路径是否存在 |
os.access() | 检查读写权限 |
os.stat() | 获取文件元数据 |
dirnames[:] = [...] | 动态跳过子目录 |
try-except包裹文件操作 | 防止程序崩溃 |
pathlib.Path().rglob() | 简洁的递归查找 |
🌐 附加资源 & 学习建议
- 📘 Python 官方文档 - os 模块
- 📘 Python 官方文档 - pathlib
- 📘 GeeksforGeeks - Python os.walk()
- 📘 Real Python - Working with Files and Directories
🎯 结语:掌握 os.walk(),就是掌握自动化核心
遍历目录是几乎所有文件处理任务的基础。通过熟练运用os模块,尤其是os.walk(),你可以构建出强大的自动化脚本,用于:
- 批量处理文件
- 日志分析
- 数据备份与迁移
- 安全扫描
- 自动化部署
🧠 记住:代码不是写出来的,是改出来的。多尝试不同的组合,多加异常处理,你的脚本才会真正“生产可用”。
🌟 今天的你,已经掌握了 Python 中最实用的文件遍历技能!
🐍现在就动手,打开你的终端,试试这段代码:
importosfordirpath,dirnames,filenamesinos.walk("/your/directory/path"):forfinfilenames:print(f"📄{os.path.join(dirpath,f)}")你会发现,原来文件管理也可以如此简单、优雅、高效!💪
✨愿你在 Python 的世界里,像os.walk()一样,不断深入,永不终止。
🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍点赞、📌收藏、📤分享给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨