如何提升21.5万条数据与1.4万个文本文件匹配复制的效率?
优化大规模文件匹配与复制的效率方案
嘿,我仔细看了你的代码,完全能理解为什么处理这么大的数据集会慢到离谱——嵌套循环的时间复杂度和冗余操作拖了后腿。咱们来一步步优化,把你的处理时间从“到8月底”压缩到几小时甚至更短:
1. 先把冗余的路径定义简化,批量处理所有季度
你现在定义了几十个单独的路径变量,不仅难维护,还没法批量处理。咱们把源路径和对应的目标路径用字典配对,这样可以循环处理所有季度,不用重复写代码:
# 用字典存储源路径和对应目标路径的映射 path_mapping = { 'D:/1994_QTR3': 'D:/Required_MDA_1994_QTR3', 'D:/1994_QTR4': 'D:/Required_MDA_1994_QTR4', 'D:/1995_QTR1': 'D:/Required_MDA_1995_QTR1', # ... 把剩下的季度都按这个格式加进来 'D:/2002/QTR4': 'D:/Required_MDA_2002_QTR4' }
2. 重构匹配逻辑:从O(N*M)降到O(N+M)
你的原代码是遍历215000行数据 → 每次遍历14000个文件,这是O(215000*14000)的操作量,完全没必要!反过来,先把需要匹配的文件名存成一个集合(集合的查找是O(1)),然后只遍历一次文件目录,检查文件是否在集合里,这样总操作量是O(215000 + 14000),速度会飞起来:
第一步:预处理Excel里的文件名,转成集合
import os import pandas as pd import shutil # 读取Excel数据,提取需要的文件名 datas = pd.read_excel(r'D:/PhD_Data/Wenrui_Filing_list/1994-2017filingslist_Wenrui_13Jul2020.xlsx') # 直接提取并处理FILE_NAME列,转成集合 target_files = set( datas['FILE_NAME'].str[26:].str.strip().dropna() # 去掉前26字符、去空格、删除空值 )
第二步:遍历每个源目录,批量复制匹配的文件
for src_dir, dest_dir in path_mapping.items(): # 确保目标目录存在,避免复制时报错 os.makedirs(dest_dir, exist_ok=True) # 遍历源目录下的所有文件 for file in os.listdir(src_dir): src_file_path = os.path.join(src_dir, file) # 只处理文件(跳过子目录) if os.path.isfile(src_file_path): # 检查文件名是否在目标集合里 if file in target_files: print(f"匹配到文件:{file},正在复制到{dest_dir}") shutil.copy(src_file_path, dest_dir)
3. 进一步提升复制速度:用硬链接代替复制(如果在同一磁盘)
如果你的源文件和目标目录在同一个磁盘分区,可以用os.link()创建硬链接,而不是shutil.copy()——硬链接不需要复制文件内容,只是给原文件加一个新的“快捷方式”,几乎瞬间完成:
把上面的shutil.copy替换成:
# 先检查目标文件是否已经存在,避免重复创建 dest_file_path = os.path.join(dest_dir, file) if not os.path.exists(dest_file_path): os.link(src_file_path, dest_file_path)
注意:硬链接只能在同一磁盘使用,如果跨磁盘还是用shutil.copy,或者用shutil.copy2(保留文件元数据)。
4. 其他小优化
- 去掉没用的模块导入:你代码里的
glob、csv、xlrd、fnmatch、string都没用到,删掉它们,减少不必要的加载。 - 用
os.scandir()代替os.listdir():os.scandir()比os.listdir()更快,因为它直接返回文件属性,不需要额外调用os.path.isfile():with os.scandir(src_dir) as entries: for entry in entries: if entry.is_file() and entry.name in target_files: shutil.copy(entry.path, dest_dir)
完整优化后的代码
import os import pandas as pd import shutil # 定义源目录与目标目录的映射 path_mapping = { 'D:/1994_QTR3': 'D:/Required_MDA_1994_QTR3', 'D:/1994_QTR4': 'D:/Required_MDA_1994_QTR4', 'D:/1995_QTR1': 'D:/Required_MDA_1995_QTR1', 'D:/1995_QTR2': 'D:/Required_MDA_1995_QTR2', 'D:/1995_QTR3': 'D:/Required_MDA_1995_QTR3', 'D:/1995_QTR4': 'D:/Required_MDA_1995_QTR4', 'D:/1996_QTR1': 'D:/Required_MDA_1996_QTR1', 'D:/1996_QTR2': 'D:/Required_MDA_1996_QTR2', 'D:/1996_QTR3': 'D:/Required_MDA_1996_QTR3', 'D:/1996_QTR4': 'D:/Required_MDA_1996_QTR4', 'D:/1997_QTR1': 'D:/Required_MDA_1997_QTR1', 'D:/1997_QTR2': 'D:/Required_MDA_1997_QTR2', 'D:/1997_QTR3': 'D:/Required_MDA_1997_QTR3', 'D:/1997_QTR4': 'D:/Required_MDA_1997_QTR4', 'D:/1998/QTR1': 'D:/Required_MDA_1998_QTR1', 'D:/1998/QTR2': 'D:/Required_MDA_1998_QTR2', 'D:/1998/QTR3': 'D:/Required_MDA_1998_QTR3', 'D:/1998/QTR4': 'D:/Required_MDA_1998_QTR4', 'D:/1999/QTR1': 'D:/Required_MDA_1999_QTR1', 'D:/1999/QTR2': 'D:/Required_MDA_1999_QTR2', 'D:/1999/QTR3': 'D:/Required_MDA_1999_QTR3', 'D:/1999/QTR4': 'D:/Required_MDA_1999_QTR4', 'D:/2000/QTR1': 'D:/Required_MDA_2000_QTR1', 'D:/2000/QTR2': 'D:/Required_MDA_2000_QTR2', 'D:/2000/QTR3': 'D:/Required_MDA_2000_QTR3', 'D:/2000/QTR4': 'D:/Required_MDA_2000_QTR4', 'D:/2001/QTR1': 'D:/Required_MDA_2001_QTR1', 'D:/2001/QTR2': 'D:/Required_MDA_2001_QTR2', 'D:/2001/QTR3': 'D:/Required_MDA_2001_QTR3', 'D:/2001/QTR4': 'D:/Required_MDA_2001_QTR4', 'D:/2002/QTR1': 'D:/Required_MDA_2002_QTR1', 'D:/2002/QTR2': 'D:/Required_MDA_2002_QTR2', 'D:/2002/QTR3': 'D:/Required_MDA_2002_QTR3', 'D:/2002/QTR4': 'D:/Required_MDA_2002_QTR4' } # 读取并预处理目标文件名集合 datas = pd.read_excel(r'D:/PhD_Data/Wenrui_Filing_list/1994-2017filingslist_Wenrui_13Jul2020.xlsx') target_files = set( datas['FILE_NAME'].str[26:].str.strip().dropna() ) # 批量处理每个季度的文件 for src_dir, dest_dir in path_mapping.items(): os.makedirs(dest_dir, exist_ok=True) # 使用os.scandir提升遍历效率 with os.scandir(src_dir) as entries: for entry in entries: if entry.is_file() and entry.name in target_files: dest_file = os.path.join(dest_dir, entry.name) # 如果同一磁盘,用硬链接替代复制 if os.path.splitdrive(src_dir)[0] == os.path.splitdrive(dest_dir)[0]: if not os.path.exists(dest_file): os.link(entry.path, dest_file) print(f"创建硬链接:{entry.name} → {dest_dir}") else: shutil.copy2(entry.path, dest_file) print(f"复制文件:{entry.name} → {dest_dir}") print("所有文件处理完成!")
内容的提问来源于stack exchange,提问作者Dale Addison
相关产品推荐
相关产品推荐

