应使用 os.walk() 而非手动递归,因其内置异常处理、不跟随符号链接、返回结构化三元组;统计文件需用 lower().endswith() 避免大小写和误匹配,配合 onerror 参数捕获 PermissionError。

直接用 os.walk() 配合计数器,比手写递归更稳、更少出错;手动递归容易漏处理异常路径或陷入符号链接循环。
为什么别自己写递归函数?
手动实现递归遍历目录时,os.listdir() + os.path.join() 组合极易忽略权限错误(PermissionError)、断开的符号链接(OSError)或循环引用。而 os.walk() 内置跳过不可读目录、默认不跟随符号链接,且返回结构清晰——每轮给出 (root, dirs, files) 三元组,天然适配统计场景。
用 os.walk() 统计指定后缀文件的正确姿势
核心是遍历 files 列表,用 str.endswith() 或 pathlib.Path.suffix 判断后缀。注意大小写和点号处理:
- 后缀字符串必须带开头的点,比如统计 Python 文件应写
'.py',不是'py' -
str.endswith()对大小写敏感,'script.PY'不会被'.py'匹配;如需忽略大小写,改用file.lower().endswith('.py') - 避免用
in filename(如'.py' in filename),会误匹配report.py.bak这类中间含点的文件名
示例代码:
立即学习“Python免费学习笔记(深入)”;
import os
<p>def count_files_by_ext(root_dir, ext):
count = 0
for dirpath, dirnames, filenames in os.walk(root_dir):
for file in filenames:
if file.lower().endswith(ext.lower()):
count += 1
return count</p><h1>统计 /tmp 下所有 .log 和 .LOG 文件</h1><p>n = count_files_by_ext('/tmp', '.log')</p>遇到 PermissionError 怎么办?
os.walk() 默认遇到无权限目录会抛 PermissionError 并中断整个遍历。必须主动捕获并跳过:
- 在
os.walk()外层加try/except不起作用,因为异常发生在迭代器内部 - 正确做法:用
onerror参数传入回调函数,例如onerror=lambda err: None可静默跳过 - 若想记录哪些路径被跳过,回调里可打印
err.filename
修正后的健壮版本:
def count_files_by_ext_safe(root_dir, ext):
count = 0
def on_error(err):
print(f"Skipped {err.filename}: {err}")
<pre class='brush:python;toolbar:false;'>for dirpath, dirnames, filenames in os.walk(root_dir, onerror=on_error):
for file in filenames:
if file.lower().endswith(ext.lower()):
count += 1
return count真正麻烦的是嵌套极深的目录或海量小文件——这时 os.walk() 的性能瓶颈比逻辑错误更值得先确认。如果路径里混着大量符号链接,记得检查是否需要设 followlinks=False(默认值,通常就该保持它)。


















