使用memmap模式的np.save与np.load在Windows 11下抛出OSError
问题分析:Windows下numpy内存映射文件写入冲突导致OSError
问题复现
运行以下代码:
import numpy as np np.save('tmp.npy', np.empty(128)) tmp = np.load('tmp.npy', mmap_mode='r+') np.save('tmp.npy', tmp[:64])
在Windows 11系统下抛出如下错误:
--------------------------------------------------------------------------- OSError Traceback (most recent call last) Cell In[1], line 4 2 np.save('tmp.npy', np.empty(128)) 3 tmp = np.load('tmp.npy', mmap_mode='r+') ----> 4 np.save('tmp.npy', tmp[:64]) File <__array_function__ internals>:180, in save(*args, **kwargs) File c:\Users\User\Documents\KULIAH\LAB_SOFTWARE\python_proj\anagrambotid\.venv\lib\site-packages\numpy\lib\npyio.py:518, in save(file, arr, allow_pickle, fix_imports) 516 if not file.endswith('.npy'): 517 file = file + '.npy' --> 518 file_ctx = open(file, "wb") 520 with file_ctx as fid: 521 arr = np.asanyarray(arr) OSError: [Errno 22] Invalid argument: 'tmp.npy'
原因解析
- Windows与Linux的文件系统锁机制存在差异:Windows对处于内存映射状态的文件会施加独占锁,不允许同一进程内的其他文件句柄以写入模式打开该文件;而Linux的文件锁策略更宽松,允许在内存映射的同时对文件进行写入操作。
- 当你用
mmap_mode='r+'加载tmp.npy后,内存映射对象会持有该文件的锁定,此时调用np.save会尝试以wb(写入二进制)模式重新打开同一个文件,Windows系统直接拒绝这个操作,从而抛出OSError。 tmp.flush()仅负责将内存映射中的数据刷回磁盘,但不会释放文件的锁定资源,因此无法解决该冲突。
解决方案
方案1:先释放内存映射锁再保存
先提取需要的切片内容并复制到内存,然后删除内存映射对象以释放文件锁,再执行保存操作:
import numpy as np np.save('tmp.npy', np.empty(128)) tmp = np.load('tmp.npy', mmap_mode='r+') # 复制切片内容到内存,脱离内存映射 arr_slice = tmp[:64].copy() # 删除内存映射对象,释放文件锁定 del tmp # 此时可以正常保存 np.save('tmp.npy', arr_slice)
方案2:直接通过内存映射修改并截断文件
如果目标是修改原文件内容并缩短长度,可以直接操作内存映射,之后手动截断文件:
import numpy as np import os np.save('tmp.npy', np.empty(128)) tmp = np.load('tmp.npy', mmap_mode='r+') # 对切片内容进行修改(示例为赋值0) tmp[:64] = np.zeros(64) # 将修改刷回磁盘 tmp.flush() # 手动截断文件到目标大小:npy文件头 + 64个元素的字节数 with open('tmp.npy', 'rb') as f: # 读取npy文件头标识与长度 magic = f.read(6) if magic == b'\x93NUMPY': f.read(2) # 跳过版本号 header_len = np.frombuffer(f.read(2), dtype=np.uint16)[0] total_header_len = 6 + 2 + 2 + header_len # 计算新文件大小(假设元素为默认float64,每个占8字节) new_size = total_header_len + 64 * 8 os.truncate('tmp.npy', new_size)
内容的提问来源于stack exchange,提问作者Muhammad Ikhwan Perwira
相关产品推荐
相关产品推荐

