You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python批量Excel转CSV时最后一个文件未关闭被锁定问题

问题产生原因

这个文件锁定问题是Windows平台下Python处理文件时的典型场景,核心诱因有3个:

  • 垃圾回收机制的延迟特性:原代码循环末尾写的file.close()和file = '',只是手动切断了变量对ExcelFile对象的引用,但Python的垃圾回收不是实时触发的——循环全部执行完后,最后一轮创建的ExcelFile对象不会被立刻回收,底层读取引擎持有的文件句柄没有被销毁,Windows系统会默认该文件仍被进程占用,阻止移动、删除操作。
  • 不同读取引擎的close实现不兼容:pandas处理Excel依赖不同的第三方引擎(xlrd处理旧版xls、openpyxl处理xlsx、pyxlsb处理xlsb),部分版本的引擎(尤其是旧版pyxlsb)的close()方法存在实现缺陷,调用后不会立刻释放文件锁,存在句柄泄漏问题。
  • 异常场景下的资源泄漏:如果某个工作表读取、CSV写入过程中抛出未捕获的异常,后续的file.close()不会被执行,也会导致文件被锁定,该场景属于偶发诱因。
修复方案

从资源管理的逻辑入手可以彻底解决这个问题,不需要修改系统配置:

  • 优先用with上下文管理器创建ExcelFile对象,上下文管理器会在代码块退出(哪怕抛出异常)时自动、强制释放文件资源,不需要手动调用close(),从语法层面避免句柄泄漏。
  • 每次处理完单个Excel文件后,显式调用垃圾回收接口,强制销毁无引用的对象,即时释放文件句柄。
  • 替换手动拼接路径、手动替换后缀的逻辑,用标准库的路径处理方法减少异常概率。

修复后的可直接运行代码如下:

import sys
import gc
import csv
import re
from os import listdir
from os.path import isfile, join, splitext
import pandas as pd

def removeEspecialCharacters(obj):
    if isinstance(obj, str) :
        retorno = re.sub('[(\x90|\x8F)]','',obj).replace("\r","").replace("\n","")
    else:
        retorno = obj
    return retorno

myFolder = r'C:\Users\myuser\Downloads\ConvertFilesToCsv'
myFiles = [f for f in listdir(myFolder) if isfile(join(myFolder, f))]

for file_name in myFiles:   
    lower_name = file_name.lower()
    if not (lower_name.endswith('.xls') or lower_name.endswith('.xlsx') or lower_name.endswith('.xlsb')):
        continue
    print(f'Converting file: {file_name}')
    file_path = join(myFolder, file_name)
    # 上下文管理器自动管理文件资源
    if lower_name.endswith('.xlsb'):
        xls_file = pd.ExcelFile(file_path, engine='pyxlsb')
    else:
        xls_file = pd.ExcelFile(file_path)
    
    with xls_file:
        for mySheetName in xls_file.sheet_names:
            df = pd.read_excel(xls_file, sheet_name=mySheetName)
            df = df.applymap(removeEspecialCharacters)
            # 用splitext安全提取无后缀文件名,避免文件名含后缀关键字时被错误截断
            base_name = splitext(file_name)[0]
            csvFileName = join(myFolder, f'{base_name}_{mySheetName}.csv')
            df.to_csv(
                csvFileName,
                encoding='utf-8-sig',
                index=False,
                sep=",",
                quoting=csv.QUOTE_NONNUMERIC,
                quotechar="\"",
                escapechar="\"",
                decimal=".",
                date_format='%Y-%m-%d'
            )
    # 处理完单个文件后强制回收资源,即时释放文件锁
    gc.collect()

补充说明:如果使用上述代码后仍存在锁定问题,可以升级对应的Excel读取引擎到最新版本,执行pip install --upgrade openpyxl xlrd pyxlsb pandas即可修复旧版本的已知句柄泄漏bug。

内容的提问来源于stack exchange,提问作者Paulo Coelho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 10:31:02