检测JSON文件是否被其他进程占用并阻止访问的代码报错排查
代码问题排查
原代码报错和逻辑失效来自两个核心问题:
- 变量名覆盖:
with open(self.name) as file语句获取的文件对象,被后续for file in psutil.process_iter()的循环变量重名覆盖,原本可读的文件句柄被替换为psutil的Process实例,执行json.load(file)时自然找不到read方法,触发AttributeError。 - 占用检测逻辑完全失效:原代码判断
if flist就抛出异常,等价于「系统中任意进程打开了任意文件就拦截访问」,完全没有校验打开的文件是否为当前选中的JSON文件;同时psutil遍历进程的方案存在权限不足、竞态条件(检测完成到打开文件的间隙文件被其他进程抢占)的天然缺陷,根本无法实现可靠的访问拦截。
可靠实现方案
核心思路:放弃「先遍历进程检测占用、再打开文件」的非原子逻辑,直接使用操作系统级独占文件锁打开目标文件:打开动作由操作系统原子性完成,打开成功即代表当前进程拿到了文件的独占访问权,其他进程会被系统直接阻止打开;打开失败则代表文件已被占用,直接弹出提示即可。
这种方案没有竞态漏洞、不需要遍历系统进程、不受权限限制,稳定性远高于psutil遍历方案。
实现代码
import os import json from PyQt5 import QtWidgets # 类内的文件打开方法 def file_open(self): # 选择目标JSON文件 self.name, _filtre = QtWidgets.QFileDialog.getOpenFileName(self.centralwidget, filter='*.json') if not self.name: # 用户取消选择直接返回 return self.file_handle = None # 全局持有文件句柄,保证锁全程生效 try: # 按平台传参,以禁止其他进程读写的独占模式打开文件 if os.name == 'nt': # Windows平台 open_flags = os.O_RDONLY | os.O_SHARE_DENY_RW else: # Linux/macOS平台 open_flags = os.O_RDONLY file_fd = os.open(self.name, open_flags) self.file_handle = os.fdopen(file_fd, 'r', encoding='utf-8') except PermissionError: # 独占打开失败 = 文件被其他进程/程序实例占用,弹框提示 tip_dialog = QtWidgets.QDialog(self) tip_dialog.setWindowTitle("文件被占用") dialog_layout = QtWidgets.QVBoxLayout(tip_dialog) tip_text = QtWidgets.QLabel(f"选中的文件已被其他程序打开,请关闭对应程序后重试") confirm_btn = QtWidgets.QPushButton("确定") confirm_btn.clicked.connect(tip_dialog.accept) dialog_layout.addWidget(tip_text) dialog_layout.addWidget(confirm_btn) tip_dialog.exec_() return # 独占锁拿到后读取JSON内容 try: self.dataTab = [] self.jsonlist = json.load(self.file_handle) self.site = self.jsonlist["site"] self.user = self.jsonlist["user"] self.project = self.jsonlist["project"] self.dt_string = self.jsonlist["Date-Time"] self.dataTab = self.jsonlist['Test'] except json.JSONDecodeError: QtWidgets.QMessageBox.critical(self, "文件错误", "选中的文件不是合法的JSON格式") self.file_handle.close() self.file_handle = None return # 注意:不要在这里关闭self.file_handle! # 需要在程序退出、用户手动关闭当前项目时再调用self.file_handle.close()释放锁 # 锁释放前其他任何进程都无法以读写模式打开该文件
注意事项
- 必须在程序运行期间全程持有
self.file_handle,如果读取完JSON就立刻关闭句柄,文件锁会自动释放,其他实例可以正常打开文件,拦截逻辑失效。 - 该方案是操作系统内核层面实现的访问控制,不会出现psutil方案的漏判、权限报错问题,性能也远高于遍历全系统进程的方案。
内容的提问来源于stack exchange,提问作者AlexM
相关产品推荐
相关产品推荐

