exklusiver filezugriff

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
kryz
User
Beiträge: 12
Registriert: Sonntag 3. Februar 2008, 16:55

Donnerstag 9. April 2009, 12:54

Hallo

Ich möchte eine Datei exklusiv öffnen, also so dass kein anderer Prozess dieselbe Datei öffnen kann. Mit open() scheint das nicht zu gehen und mit os.open auch nicht (oder hab ich da was übersehen?). gibt es einen (einfachen) weg, ein solches file-objekt zu erstellen?

p.s. das ganze sollte auf windows xp mit python 2.5 laufen
DasIch
User
Beiträge: 2462
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Donnerstag 9. April 2009, 13:04

Es geht nicht.
Benutzeravatar
kbr
User
Beiträge: 916
Registriert: Mittwoch 15. Oktober 2008, 09:27

Donnerstag 9. April 2009, 13:43

Falls diese Exklusivität nur für eine Applikation gelten soll, die parallel in mehreren Prozessen läuft, so geht es mit einem kleinen Trick: teste vor dem öffnen auf die Existenz der Datei "dateiname.lock" und unterbinde das öffnen der eigentlichen Datei "dateiname", falls die lock-Datei existiert. Andernfalls erzeuge die Datei "dateiname.lock" und öffne dann die eigentliche Datei. Beim schließen nicht vergessen, die Datei "dateiname.lock" wieder zu löschen. Unter UNIX geht das mit lock-handles eleganter, aber so funktioniert es auch bei Windows.
Nergal
User
Beiträge: 72
Registriert: Montag 6. Oktober 2008, 14:02

Donnerstag 9. April 2009, 14:26

kbr hat geschrieben:Falls diese Exklusivität nur für eine Applikation gelten soll, die parallel in mehreren Prozessen läuft, so geht es mit einem kleinen Trick: teste vor dem öffnen auf die Existenz der Datei "dateiname.lock" und unterbinde das öffnen der eigentlichen Datei "dateiname", falls die lock-Datei existiert. Andernfalls erzeuge die Datei "dateiname.lock" und öffne dann die eigentliche Datei. Beim schließen nicht vergessen, die Datei "dateiname.lock" wieder zu löschen. Unter UNIX geht das mit lock-handles eleganter, aber so funktioniert es auch bei Windows.
Das Modul msvcrt bietet etwas ähnliches.

Code: Alles auswählen

>>> import os
>>> import msvcrt
>>> FileName = "E:\\test.txt"
>>> AccessOne = open(FileName)
>>> msvcrt.locking(AccessOne.fileno(), msvcrt.LK_LOCK, os.path.getsize(FileName))
>>> AccessTwo = open(FileName)
>>> msvcrt.locking(AccessTwo.fileno(), msvcrt.LK_LOCK, os.path.getsize(FileName))
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
IOError: [Errno 36] Resource deadlock avoided
>>> 
Falls die Datei schon gelockt ist, wird ein IOError geworfen.

Die Function locking versucht glaubich 10x die Datei zu locken; nicht wundern, wenn es etwas dauert bis die Exception geworfen wird.
lunar

Donnerstag 9. April 2009, 14:42

@kbr
Man darf nicht testen, ob die Lock-Datei existiert. Man muss versuchen, sie sofort atomar zu öffnen, ansonsten existiert eine Race Condition. Dazu lässt sich die Funktion "open()" auch nicht verwenden, man muss auf "os.open()" zurückgreifen.

Außerdem sollte Windows doch von Haus aus mandatory locks beim Öffnen einer Datei erzeugen, oder nicht?
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 9. April 2009, 15:32

Aber diese Locks gelten nicht fürs öffnen und lesen. Das geht weiterhin. Löschen kann man geöffnete Dateien zum Beispiel nicht.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
kryz
User
Beiträge: 12
Registriert: Sonntag 3. Februar 2008, 16:55

Donnerstag 9. April 2009, 16:22

Danke für die Antworten.

Leider funktioniert msvcrt.locking nicht für leere Dateien, ist also auch unzuverlässig.

Man könnte versuchen, die Datei umzubenennen, das geht nicht, wenn die Datei bereits geöffnet ist. Aber das ist wohl auch nicht ganz sauber.

So bleibt mir halt nur, meine eigene File Klasse auf basis von win32file zu programmieren. momentan brauche ich zum glück nur ein lock beim schreiben...

Code: Alles auswählen

import win32file

class LockedFile(object):

    def __init__(self, filePath):
        dwDesiredAccess = win32file.GENERIC_WRITE
        dwCreationDisposition = win32file.CREATE_ALWAYS        
        dwShareMode = 0  # locked für alle zugriffe
        lpSecurityAttributes = None
        dwFlagsAndAttributes = win32file.FILE_ATTRIBUTE_NORMAL
        hTemplateFile = None

        self._handle = win32file.CreateFile(filePath,
                                            dwDesiredAccess,
                                            dwShareMode,
                                            lpSecurityAttributes,
                                            dwCreationDisposition,
                                            dwFlagsAndAttributes,
                                            hTemplateFile)

    def write(self, str):
        str = str.replace('\n', '\r\n')
        win32file.WriteFile(self._handle, str)
        
    def close(self):
        self._handle.close()
DasIch
User
Beiträge: 2462
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Donnerstag 9. April 2009, 16:51

PEP 8 wo versteckst du dich bloß? :cry:
lunar

Donnerstag 9. April 2009, 17:46

Die Schnittstelle der Klasse hält sich an PEP 8 ... die lokalen Namen in __init__() zwar nicht, nur kann man das in diesem Fall durchaus mit den Namen der Parameter rechtfertigen. So sieht die Windows-API nun mal aus, daher halte ich es sogar für sinnvoller, sich beim Umgang damit auch an ihre Konventionen zu halten, das fördert das Verständnis.

Man kann es mit PEP 8 auch übertreiben ...
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 9. April 2009, 19:45

``str`` zu überschreiben ist aber so oder so keine gute Idee, gerade weil ``str()`` sicherlich unter den Top 10 der am meisten genutzten Builtins ist.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
lunar

Donnerstag 9. April 2009, 19:49

Leonidas hat geschrieben:``str`` zu überschreiben ist aber so oder so keine gute Idee, gerade weil ``str()`` sicherlich unter den Top 10 der am meisten genutzten Builtins ist.
Sicher, aber auf zwei Zeilen Code bringt das auch niemanden um ;)
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 9. April 2009, 20:10

lunar hat geschrieben:Sicher, aber auf zwei Zeilen Code bringt das auch niemanden um ;)
Natürlich nicht, aber als jemand der sich mehr als einmal gewundert hat warum Funktionen auf einmal nicht mehr funktionieren wird man vorsichtiger :)
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
HerrHagen
User
Beiträge: 430
Registriert: Freitag 6. Juni 2008, 19:07

Donnerstag 9. April 2009, 21:58

str zu überschreiben halt ich auch für unschön. Allerdings muss ich sagen das mir die ständigen Hinweise auf PEP8 doch ein wenig auf die Nerven gehen.
Gerade beim Überschreiben von builtins in der Stdlib war man auch nicht gerade zimperlich. Man schaue sich bswp. pickle.py (Py2.5, Zeile 1372) an:

Code: Alles auswählen

def loads(str):
    file = StringIO(str)
    return Unpickler(file).load()
Hier wird gleich str und file überschrieben :wink:. Und das auch mit anderen builtins an vielen anderen Stellen.

MFG HerrHagen
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 9. April 2009, 22:10

Die Stdlib ist ja auch kein besonders gutes Beispiel für guten Code. Oder PEP8-Konformität.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
kbr
User
Beiträge: 916
Registriert: Mittwoch 15. Oktober 2008, 09:27

Donnerstag 9. April 2009, 23:13

lunar hat geschrieben:@kbr
Man darf nicht testen, ob die Lock-Datei existiert. Man muss versuchen, sie sofort atomar zu öffnen, ansonsten existiert eine Race Condition. Dazu lässt sich die Funktion "open()" auch nicht verwenden, man muss auf "os.open()" zurückgreifen.
@lunar
Ich bin mir nicht sicher, ob ich das mit der Race Condition in diesem Fall verstanden habe. Nehmen wir an, dass os.path.exists(), open() bzw. os.open() alle atomar seien. Dennoch wird (os.)open() bei Mißerfolg nicht gleichzeitig eine Exception auslösen und eine neue Datei anlegen. D.h. die Lösung mit einem separatem Lockfile wird immer das Problem haben, dass nach einem Zugriff (mit (os.)open() oder exists()), aber vor Anlegen der Lock-Datei, der Prozeß wechselt und beide Prozesse davon ausgehen, lese- und schreib-berechtigt zu sein. D.h. wirklich zuverlässig wäre das ganze nur auf OS-Ebene zu lösen.
Antworten