Python脚本文件名循环遍历CPU占用过高,如何优化?
解决大量文件场景下生成文件名的CPU占用过高问题
你的问题很典型:当文件数量达到几千级时,逐个调用os.path.exists()检查文件名会产生大量磁盘IO操作——磁盘本身是慢设备,CPU会频繁等待IO完成,最终导致占用率飙升。咱们来拆解问题,一步步优化:
原代码的核心问题
原代码的逻辑是从number=1开始,逐个生成文件名并检查是否存在:
number = 1 while True: fname = "Capture_" + str(number) + ".jpg" if not os.path.exists(fname): break number = number + 1 DoSomething(fname)
每循环一次就触发一次磁盘查询,5000个文件就要做5000次IO,这是性能瓶颈的根源。
优化思路:批量获取+数字排序
你提到用max(glob.glob('Capture_*.jpg'))会遇到字符串排序的坑(比如Capture_999.jpg会被当成比Capture_1000.jpg大的字符串),这个问题的关键是要从文件名里提取数字值,而不是直接比较字符串。
优化后的代码(基础版)
我们可以一次性获取所有匹配的文件,提取每个文件名中的数字,排序后处理文件并得到下一个编号:
import glob # 1. 批量获取所有符合格式的文件 matched_files = glob.glob('Capture_*.jpg') # 2. 提取文件名中的数字,过滤无效文件 valid_entries = [] for file in matched_files: try: # 拆分文件名:Capture_123.jpg → 提取123 num_str = file.split('_')[1].split('.')[0] num = int(num_str) valid_entries.append( (num, file) ) except (IndexError, ValueError): # 忽略命名不符合规则的文件 continue # 3. 按数字从小到大排序,保证处理顺序和原逻辑一致 valid_entries.sort() # 4. 处理所有已存在的文件 for num, fname in valid_entries: DoSomething(fname) # 5. 获取下一个可用编号(如果没有文件则从1开始) next_number = max( [entry[0] for entry in valid_entries], default=0 ) + 1 new_fname = f"Capture_{next_number}.jpg"
更高效的进阶版:用os.scandir()
如果文件数量特别大(比如几万级),os.scandir()比glob更高效——它直接从操作系统获取目录条目信息,减少了额外的系统调用:
import os valid_entries = [] with os.scandir('.') as entries: for entry in entries: # 只处理文件,且符合命名规则 if entry.is_file() and entry.name.startswith('Capture_') and entry.name.endswith('.jpg'): try: num = int(entry.name.split('_')[1].split('.')[0]) valid_entries.append( (num, entry.name) ) except (IndexError, ValueError): continue # 后续排序、处理、获取编号的逻辑和上面一致 valid_entries.sort() for num, fname in valid_entries: DoSomething(fname) next_number = max( [entry[0] for entry in valid_entries], default=0 ) + 1 new_fname = f"Capture_{next_number}.jpg"
为什么这样优化?
- 减少磁盘IO次数:从原来的几千次IO变成1次(批量获取文件),彻底解决CPU等待IO的问题;
- 正确获取最大编号:通过提取数字值比较,避免了字符串排序的陷阱;
- 处理逻辑更清晰:把「查找文件」「处理文件」「生成新编号」拆分开,可读性和可维护性更好。
内容的提问来源于stack exchange,提问作者Naveenchandar
相关产品推荐
相关产品推荐

