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

OpenPyXl保存工作簿偶发PermissionError报错,如何捕获并重试?

故障根因
  • 核心是Windows文件系统的锁冲突:VBA调用Scripting.FileSystemObject的CopyFile方法时,会对源数据工作簿加共享读锁,此时Python侧openpyxl执行save操作需要以独占写模式打开xlsx文件(xlsx本质是ZIP压缩包,写入操作要求独占权限),二者时间窗口重叠时就会触发PermissionError: [Errno 13]报错。
  • 之前编写的重试逻辑完全不生效的原因是代码里写的是wb.save(仅引用方法对象),没有加括号执行wb.save(FileName)调用,所以既不会触发异常捕获,也不会实际执行文件保存操作。
解决方案

1. 优先修复Python侧重试逻辑(改造成本极低,可解决99%以上的现有故障)

替换原有保存逻辑,先写入临时文件再原子替换原文件,减少锁冲突的时间窗口,同时完善重试逻辑:

import os
import time

retries = 5
success = False
temp_file = FileName + ".tmp"

while not success and retries > 0:
    try:
        # 先保存到临时文件,避免写入过程中被抢锁损坏原文件
        wb.save(temp_file)
        # 原子替换原文件,Windows下该操作锁时间极短,冲突概率极低
        os.replace(temp_file, FileName)
        success = True
    except (PermissionError, OSError) as saveerror:
        retries -= 1
        print(f'>>> Save Error: {saveerror}, 剩余重试次数: {retries}')
        time.sleep(2)

if not success:
    # 重试全部失败可记录告警日志,不要直接终止进程
    print(f'!!! 保存文件{FileName}多次失败,请检查文件占用情况')
    # 可选:备份当前内存数据到其他路径避免丢失
    wb.save(FileName + f".bak_{int(time.time())}")

该方案不需要修改任何VBA代码,上线后即可解决现有偶发崩溃问题。

2. VBA侧可选优化(进一步降低冲突概率)

不需要重构现有VBA逻辑,仅在执行CopyFile前增加文件占用判断,避免在Python写入时触发复制:

Function IsFileLocked(filePath As String) As Boolean
    On Error Resume Next
    Open filePath For Binary Access Read Write Lock Read Write As #1
    Close #1
    IsFileLocked = Err.Number <> 0
    Err.Clear
End Function

' 原有复制逻辑前增加重试判断
Dim copyRetries As Integer
copyRetries = 3
Do While IsFileLocked(strFromFilePath) And copyRetries > 0
    copyRetries = copyRetries - 1
    Application.Wait (Now + TimeValue("0:00:01"))
Loop
If copyRetries > 0 Then
    fso.CopyFile strFromFilePath, strFilePath, True
End If

3. 长期优化可选方案

如果后续希望彻底消除冲突,可以使用ADODB直接读取未打开的xlsx文件数据,不需要复制文件也不需要打开Excel实例,现有VBA逻辑仅需要修改数据读取部分,不需要全量重构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 18:15:01