Windows下WxPython使用pylightxl读取已打开Excel报权限错误
问题原因
Windows平台下,Excel打开.xlsx文件时会默认持有文件句柄并加写锁,即便你已经把修改内容保存到磁盘,Excel也不会释放该锁,默认禁止其他进程以常规读写模式访问文件。无论是wx文件选择器弹出的占用提示,还是pylightxl抛出的PermissionError,本质都是触发了这个文件锁限制,和文件是否保存无关。
解决方法
核心逻辑是读取文件时仅申请读权限,同时开启文件共享模式,不抢占Excel持有的写权限,先把文件内容读到内存后再交给pylightxl解析,全程不会和Excel的锁冲突。你只需要修改两处代码即可:
- 调整文件选择控件的参数,关闭控件默认的文件独占校验,避免选文件时就弹出占用警告
- 修改文件读取逻辑,用共享读模式获取文件内容,绕开Excel的锁限制
具体修改
- 调整文件选择控件初始化的style参数,加上
wx.FLP_NO_VALIDATE:
self.m_filePicker1 = wx.FilePickerCtrl( self, wx.ID_ANY, wx.EmptyString, u"Select a file", u"*.xlsx", wx.DefaultPosition, wx.DefaultSize, wx.FLP_OPEN | wx.FLP_NO_VALIDATE )
- 替换原有的
print_sheet_names函数,新增共享读逻辑,修改后头部导入和函数代码如下:
import io import os import sys import wx import wx.xrc import pylightxl as xl # Windows平台兼容共享读 if sys.platform == "win32": import ctypes import msvcrt from ctypes import wintypes kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) GENERIC_READ = 0x80000000 FILE_SHARE_READ = 0x00000001 FILE_SHARE_WRITE = 0x00000002 FILE_SHARE_DELETE = 0x00000004 OPEN_EXISTING = 3 FILE_ATTRIBUTE_NORMAL = 0x80 def shared_read_open(file_path): handle = kernel32.CreateFileW( file_path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, None, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, None ) if handle == wintypes.HANDLE(-1).value: raise ctypes.WinError(ctypes.get_last_error()) # 将win32句柄包装为Python可操作的文件对象 return os.fdopen(msvcrt.open_osfhandle(handle, os.O_RDONLY), 'rb') else: def shared_read_open(file_path): return open(file_path, 'rb') def print_sheet_names(file): # 先将文件内容读入内存,再交给pylightxl解析 with shared_read_open(file) as f: file_stream = io.BytesIO(f.read()) db = xl.readxl(file_stream) for name in db.ws_names: print(name)
说明
- 修改后无需关闭已打开的Excel文件即可正常读取,读到的内容是磁盘上最新保存的版本,Excel中未保存的修改不会被读取,符合读取落盘数据的需求
- 不需要替换现有依赖,原有wx交互、pylightxl解析逻辑都可以保留
- 非Windows平台下代码会自动走普通文件读取逻辑,没有兼容性问题
内容的提问来源于stack exchange,提问作者MarshalH
相关产品推荐
相关产品推荐

