2017-11-02 21 views
3

私はコンテキストマネージャーであるmmapを使用するコンテキストマネージャを作成しようとしています。当初私はオープンファイルの問題を抱えていました[なぜPermissionError:[WinError 32]を取得していないのですか?] hereと答えがすぐにと答えた理由はです。なぜコンテキストマネージャはファイルディスクリプタを閉じていませんか?

この情報があれば、私は問題を修正する2つの方法を試みましたが、どちらも問題なく動作しています。

最初のアプローチは、contextlib@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__ 

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は、バックこれはあなたが作成された出力で見ることができるようにファイルディスクリプタはそのバージョンで閉じだったので、本当に私を混乱させる:だから、私は再びこだわっているようだ

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' 

。何が間違っているか(そしてそれを修正する方法)のアイデア?また、彼らは両方の問題を解決することができます、あなたは意見がある場合はどちらが良いですか?

ソリューション

両方のスニペット中にエラーが発生しました。これは最初の簡単な誤植でした。 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__()方法、ちょうど関連したファイルディスクリプタに閉鎖されていなかったため。それは私には起こりませんでした。なぜなら、発生した例外は最初のケースと同じだったからです。 2番目の試みの場合

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') 
+0

を?私はそのエラーだけを読んだ。 https://stackoverflow.com/questions/27215462/file-handling-in-python-permissionerror-werror-32-the-process-cannot-acce –

+2

'#contextmanager'は' @ contextmanager'ではありません。 – user2357112

+0

また、 "in finally clause"は実際には 'finally'節にはありません。 – user2357112

答えて

2

、あなたは、メモリマップドファイルクローズする必要があります。これはあなたを助ける

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') 
+0

正式な回答として投稿して以来、これを受け入れるでしょう...ありがとう。それは私の質問の下のコメントと一緒に両方のバージョンの修正を提供しています。私は 'mmap'オブジェクトの終了とそれに関連するファイルのクローズを混同し続けていると思います。 – martineau

+0

Windowsでは、1つ以上のプロセスでファイルにアクセスできません。ファイルオブジェクトの前にmmapオブジェクトを閉じる必要があります。答えは正しい。 –

関連する問題