2016-10-23 1 views
0

Ich versuche, eine Datei in Python mit Win32Api zu lesen, um in der Lage zu sein, die Datei zu öffnen, ohne es auf einem Windows-System zu sperren.Windows: Iterate auf eine Datei in Python mit Win32API

Ich konnte die Datei öffnen und sogar lesen, aber wenn ich versuche, das Iterator-Protokoll zu implementieren, erhalte ich eine Fehlermeldung, die ich nicht verstehen kann.

Hier ist ein Beispiel-Skript, das das Problem

#!/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) 

Jetzt reproduzieren, wenn Sie versuchen, dieses Skript auszuführen, diese Fehlermeldung erhalten:

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 

Wenn ich den kommentierten Code Kommentar- in die "open" -Methode Ich kann die ganze Datei lesen, daher glaube ich nicht, dass das Problem in der Verwendung der Win32 API liegt, um die Datei zu öffnen ... also ... was ich vermisse?

Warum mit dem Iterator-Protokoll bekomme ich die Fehlermeldung? Ist es ein thread-ähnliches Problem? Wie kann ich es reparieren?

Ich weiß, dass es wahrscheinlich tausend um arbeits sein wird, aber ich möchte verstehen, warum dieser Code nicht funktioniert ...

Vielen Dank für die Hilfe wird Ihnen und sorry für meine sehr schlecht Englisch ... :(

Dave

+0

Nur eine Vermutung hier: Können Sie versuchen, 'handle' und' file_descriptor' von Ihrer 'open' Methode als Instanzattribute zu speichern? Es scheint, als ob das GC diese Griffe freigibt. Deshalb funktioniert es, wenn Sie die Datei innerhalb derselben Methode lesen. – Wombatz

+0

Wombatz ... DANKE !!! Sie haben recht, speichern Sie einfach den Griff in einer Instanz Attribut machen es wie ein Charme, danke! PS wenn du antwortest, werde ich deine als die richtige Antwort genehmigen. – mastro35

+0

Bedeuten Sie, dass ein Standard 'open (Pfad, 'r')' die Datei unter Windows sperrt? –

Antwort

0

Das Problem ist, dass die Objekte handle und file_descriptor könnten Müll nach der Funktion open kehrt gesammelt bekommen. Wenn Sie __next__ die Objekte nennen könnte befreit worden, die wirft die OSError: [Errno 9] Bad file descriptor. Deshalb funktioniert es auch, wenn Sie die Datei in der Open-Funktion selbst lesen, da dort die Objekte noch vorhanden sind.

Um dies zu lösen, speichern Sie die Objekte einfach als Instanzattribute, so dass es mindestens einen Verweis darauf gibt.

Es könnte ausreichen, nur einen von ihnen zu speichern, aber ich bin mir nicht sicher welcher. Das Speichern von beiden ist der sichere Weg.

+0

'file_descriptor' ist nur eine Ganzzahl.Der richtige Umgang mit 'handle' besteht auch darin, nach dem Aufruf von' open_osfhandle' die 'Detach'-Methode aufzurufen und keinen Verweis darauf zu behalten. Andernfalls haben Sie eine Race-Bedingung, welche den Griff zuerst schließt. Windows verwendet Handles erneut, sodass einer von ihnen den Handle für ein Kernelobjekt schließen kann, das vollständig unabhängig ist (eine andere Datei, ein Thread, ein Prozess, ein Ereignis, ein Semaphor usw.). – eryksun

+0

@eryksun sollten Sie eine Antwort dafür erstellen. Dann lösche ich dieses und op kann deine annehmen. – Wombatz