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
相关产品推荐
相关产品推荐

