如何用Python实现文件路径列表中同序列文件的分组处理?
你的当前方案用路径长度来分组显然行不通——按字符串长度分组完全没考虑序列的实际结构和文件夹上下文。我们换个思路,聚焦两个关键信息:文件夹路径(用来区分不同目录下的内容)和序列基础名称(文件名中帧号之前的部分,用来识别属于同一序列的文件)。
核心思路
- 对每个路径,拆分出文件夹路径、文件名和扩展名;
- 用正则表达式识别文件名中的帧号(影视行业常见命名是帧号在文件名末尾,前缀是下划线或点,比如
_1025或.1025); - 以「文件夹路径 + 序列基础名称」作为分组键,这样同一文件夹下的同一序列文件会被归为一组;
- 先按分组键排序(因为
itertools.groupby只会把连续的相同键分到一组),再按帧号排序,保证分组后的序列是有序的。
完整实现代码
import os import re import itertools import pprint lpaths = [ '/projects/0100/dbu/shots/11_1/SC11_1_Shot012/render/SC11_1_Shot012.v01_1025.exr', '/projects/0100/dbu/shots/11_1/SC11_1_Shot012/render/SC11_1_Shot012.v01_1042.exr', '/projects/0100/dbu/shots/11_1/SC11_1_Shot012/render/SC11_1_Shot012.v01_1016.exr', '/projects/0100/dbu/shots/11_1/SC11_1_Shot012/2d/app/Shot012_v1.exr', '/projects/0100/dbu/shots/11_1/SC11_1_Shot012/2d/app/Shot012_v02.exr', '/projects/0100/dbu/shots/11_1/SC11_1_Shot004/3d/app2/workspace.cfg', '/projects/0100/dbu/shots/11_1/SC11_1_Shot004/3d/app2/scenes/SC11_1_Shot004_v01.exr', '/projects/0100/dbu/shots/11_1/SC11_1_Shot004/3d/app2/scenes/Shot004_camera_v01.exr', '/projects/0100/dbu/shots/11_1/SC11_1_Shot004/render/SC11_1_Shot004.v01_1112.exr', '/projects/0100/dbu/shots/11_1/SC11_1_Shot004/render/SC11_1_Shot004.v01_1034.exr', '/projects/0100/dbu/shots/11_1/SC11_1_Shot004/render/SC11_1_Shot004.v02_1116.exr', '/projects/0100/dbu/shots/11_1/SC11_1_Shot004/render/SC11_1_Shot004.v02_1126.exr' ] def get_sequence_info(path): # 获取文件夹路径 folder = os.path.dirname(path) # 获取文件名(含扩展名) filename = os.path.basename(path) # 拆分文件名和扩展名 name_without_ext, ext = os.path.splitext(filename) # 匹配文件名末尾的帧号:前面是_或.,后面是一串数字 frame_match = re.search(r'([._])(\d+)$', name_without_ext) if frame_match: # 提取序列基础名称(去掉帧号部分) sequence_base = name_without_ext[:frame_match.start()] # 提取帧号并转为整数,方便排序 frame_number = int(frame_match.group(2)) else: # 没有帧号的文件,自身作为一个单帧序列 sequence_base = name_without_ext frame_number = 0 # 分组键:文件夹路径 + 序列基础名称,确保同文件夹同序列的文件被分到一组 group_key = (folder, sequence_base) return group_key, frame_number, path # 1. 为每个路径生成分组键、帧号和原路径 path_info = [get_sequence_info(p) for p in lpaths] # 2. 先按分组键排序,再按帧号排序——groupby要求相同键的元素连续排列 sorted_path_info = sorted(path_info, key=lambda x: (x[0], x[1])) # 3. 按分组键进行分组 sequence_groups = {} for key, group in itertools.groupby(sorted_path_info, key=lambda x: x[0]): # 提取每组中的路径,已经按帧号排好序 sequence_paths = [item[2] for item in group] sequence_groups[key] = sequence_paths # 打印分组结果 pprint.pprint(sequence_groups)
代码说明
get_sequence_info函数:负责解析每个路径的关键信息,识别帧号并生成分组键;- 排序步骤:必须先按分组键排序,否则
itertools.groupby会把同一序列的分散文件分成多个组; - 正则表达式:
r'([._])(\d+)$'匹配文件名末尾的数字帧号,如果你有特殊的命名规则(比如帧号在中间、分隔符不同),可以调整这个正则来适配。
输出结果示例
运行后,你会得到一个字典,每个键是(文件夹路径, 序列基础名称),对应的值是该序列的所有路径(按帧号有序):
- 比如
('/projects/0100/dbu/shots/11_1/SC11_1_Shot012/render', 'SC11_1_Shot012.v01')对应的列表是三个按帧号排序的EXR文件; - 单文件(比如
Shot012_v1.exr)会单独作为一个长度为1的序列组。
内容的提问来源于stack exchange,提问作者Desmond
相关产品推荐
相关产品推荐

