我试图创build一个使用mmap
的上下文pipe理器,这本身就是一个上下文pipe理器。 最初我有一个愚蠢的开放文件问题[为什么不是mmapclosures相关文件(获取PermissionError:[WinError 32])?] 在这里 ,一个答案很快就解释了为什么它不能按需要工作。
鉴于这些信息,我试图用两种不同的方法来纠正这个问题,但都没有成功。
第一种方法是使用@contextmanager
装饰器:
from contextlib import contextmanager import os import mmap #contextmanager def memory_map(filename, access=mmap.ACCESS_WRITE): size = os.path.getsize(filename) fd = os.open(filename, os.O_RDWR) print('about to yield') with mmap.mmap(fd, size, access=access) as m: yield m print('in finally clause') os.close(fd) # Close the associated file descriptor. test_filename = 'data' # First create the test file. size = 1000000 with open(test_filename, 'wb') as f: f.seek(size - 1) f.write(b'\x00') # Read and modify mmapped file in-place. with memory_map(test_filename) as m: # Causes AttributeError: __enter__ print(len(m)) print(m[0:10]) # Reassign a slice. m[0:11] = b'Hello World' # Verify that changes were made print('reading back') with open(test_filename, 'rb') as f: print(f.read(11)) # Delete test file. # Causes: # PermissionError: [WinError 32] The process cannot access the file because it # is being used by another process: 'data' os.remove(test_filename)
但结果是:
Traceback (most recent call last): File "memory_map.py", line 27, in <module> with memory_map(test_filename) as m: # Causes AttributeError: __enter__ AttributeError: __enter__
在下一次尝试中,我试图明确创build一个上下文pipe理器类:
import os import mmap class MemoryMap: def __init__(self, filename, access=mmap.ACCESS_WRITE): print('in MemoryMap.__init__') size = os.path.getsize(filename) self.fd = os.open(filename, os.O_RDWR) self.mmap = mmap.mmap(self.fd, size, access=access) def __enter__(self): print('in MemoryMap.__enter__') return self.mmap def __exit__(self, exc_type, exc_value, traceback): print('in MemoryMap.__exit__') os.close(self.fd) # Close the associated file descriptor. print(' file descriptor closed') test_filename = 'data' # First create the test file. size = 1000000 with open(test_filename, 'wb') as f: f.seek(size - 1) f.write(b'\x00') # Read and modify mmapped file in-place. with MemoryMap(test_filename) as m: print(len(m)) print(m[0:10]) # Reassign a slice. m[0:11] = b'Hello World' # Verify that changes were made print('reading back') with open(test_filename, 'rb') as f: print(f.read(11)) # Delete test file. # Causes PermissionError: [WinError 32] The process cannot access the file # because it is being used by another process: 'data' os.remove(test_filename)
这使得它更进一步,但是PermissionError
又回来了 – 这让我很困惑,因为文件描述符在该版本中被closures了,就像你在输出中看到的那样:
in MemoryMap.__init__ in MemoryMap.__enter__ 1000000 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' in MemoryMap.__exit__ file descriptor closed reading back b'Hello World' Traceback (most recent call last): File "memory_map2.py", line 47, in <module> os.remove(test_filename) PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'data'
所以看来我又被卡住了。 任何想法是什么错误(以及如何解决它)? 此外,如果他们都可以修复,哪一个更好,如果你有意见?
解决scheme
这两个片段都有错误。 首先是一个简单的印刷错误。 contextmanger
装饰者被注释掉了。 本来应该:
@contextmanager # Leading "#" changed to "@". def memory_map(filename, access=mmap.ACCESS_WRITE): size = os.path.getsize(filename) fd = os.open(filename, os.O_RDWR) ,,,
第二个是因为mmap
本身并没有在__exit__()
方法中closures,只是关联的文件描述符。 这从来没有发生过,因为提出的例外情况与第一种情况相同。
def __exit__(self, exc_type, exc_value, traceback): print('in MemoryMap.__exit__') self.mmap.close() # ADDED. os.close(self.fd) # Close the associated file descriptor. print(' file descriptor closed')
如果你第二次尝试,你需要关闭内存映射文件:
def __exit__(self, exc_type, exc_value, traceback): self.mm.close() print('in MemoryMap.__exit__') os.close(self.fd) # Close the associated file descriptor. print(' file descriptor closed')