2016-10-23 17 views
0

Windowsシステムでファイルをロックせずにファイルを開くことができるように、PythonでWin32Apiを使用してファイルを読み取ろうとしています。Windows:PythonでWin32APIを使用してファイルを反復する

私はファイルを開いたり読み込んだりできましたが、イテレータプロトコルを実装しようとすると、私が理解できないエラーメッセージが表示されます。私はコメントしたコードのコメントを解除した場合

Traceback (most recent call last): 
    File "C:\Users\me\Desktop\prova.py", line 63, in <module> 
    for line in my_file: 
    File "C:\Users\me\Desktop\prova.py", line 53, in __next__ 
    line = self.fh.readline() 
OSError: [Errno 9] Bad file descriptor 

:ここ

は、このスクリプトを実行しようとした場合、このエラーメッセージが表示されますが、問題は今

#!/usr/bin/env python 

import os 


class FileTail(object): 
    def __init__(self, file): 
     self.open(file) 

    def open(self, file): 
     """Open the file to tail and initialize our state.""" 
     fh = None 

     import win32file 
     import msvcrt 

     handle = win32file.CreateFile(file, 
             win32file.GENERIC_READ, 
             win32file.FILE_SHARE_DELETE | 
             win32file.FILE_SHARE_READ | 
             win32file.FILE_SHARE_WRITE, 
             None, 
             win32file.OPEN_EXISTING, 
             0, 
             None) 
     file_descriptor = msvcrt.open_osfhandle(
      handle, os.O_TEXT | os.O_RDONLY) 

     fh = open(file_descriptor, encoding='utf-8', 
        errors='ignore', newline="\n") 

     self.reopen_check = "time" 

     self.fh = fh 
     self.file = file 

     # Uncommenting this code demonstrate that there's no problem reading the file!!!! 
     # ------------------------------------------------------------------------------- 
     # line = None 
     # self.wait_count = 0 

     # while not line: 
     #  line = self.fh.readline() 

    def __iter__(self): 
     return self 

    def __next__(self): 
     line = None 
     self.wait_count = 0 

     while not line: 
      line = self.fh.readline() 

     return line 

# ############################## 
# ENTRY POINT 
# ############################## 
if __name__ == "__main__": 
    my_file = FileTail('C:\LOGS\DANNI.WEB\PROVA.LOG') 

    for line in my_file: 
     print(line) 

を再現するスクリプトの例です"オープン"メソッド私はファイル全体を読むことができるので、私は問題がファイルを開くためにwin32 APIの使用にあるとは思わない...だから...私は何が欠けているの?

なぜイテレータプロトコルを使用すると、エラーメッセージが表示されますか?それはスレッド関連の問題ですか?どうすれば修正できますか?

は私の非常に悪いため、あなたが提供する助けと申し訳ありませんありがとうございました...私は仕事の周りの、おそらく数千があるだろうことを知っているが、私はこのコードが動作しない理由を理解したいです英語... :(

デイブ

+0

ここで推測するとおり、 'open'メソッドの' handle'と 'file_descriptor'をインスタンス属性として保存しようとしますか? gcがそれらのハンドルを解放しているようです。そのため、同じメソッドの中でファイルを読み込んだときに動作します。 – Wombatz

+0

Wombatz ...ありがとうございます!あなたは正しいです、インスタンス属性にハンドルを格納するだけで、それは魅力のように動作します、ありがとう!あなたが答えたら私は正しい答えとしてあなたを承認します。 – mastro35

+0

標準の 'open(path、 'r')'がWindows上でファイルをロックすることを暗示していますか? –

答えて

0

問題は、オブジェクトhandlefile_descriptorはゴミが機能open戻った後、回収される可能性がありますということです。 あなたが__next__を呼び出すときにオブジェクトが提起され解放されている可能性がありますOSError: [Errno 9] Bad file descriptor。これは、オブジェクトがまだ存在しているので、開いている関数自体でファイルを読み込んだときに動作する理由です。

これを解決するには、オブジェクトをインスタンス属性として格納するだけで、オブジェクトに少なくとも1つの参照が存在するようにします。

def open(...) 
    ... 
    self.handle = CreateFile(...) 
    ... 
    self.file_descriptor = msvcrt.open_osfhandle(self.handle, ...) 
    ... 
    self.fh = open(self.file_descriptor, ...) 
    ... 

いずれか1つのみを保存すれば十分かもしれませんが、わかりません。両方を保存するのが節約方法です。

+0

'file_descriptor'は単なる整数です。また、 'handle'を扱う適切な方法は、' open_osfhandle'を呼び出した後、 'Detach'メソッドを呼び出すことです。さもなければ、ハンドルを最初に閉じる競合状態があります。 Windowsはハンドルを再利用するため、それらのうちの1つは完全に無関係のカーネルオブジェクト(別のファイル、スレッド、プロセス、イベント、セマフォなど)のハンドルを閉じることになります。 – eryksun

+0

@eryksunあなたはその答えを作成する必要があります。それから私はこの1つを削除し、opはあなたを受け入れることができます。 – Wombatz

関連する問題