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
exklusiver filezugriff
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.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.
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
>>>
Die Function locking versucht glaubich 10x die Datei zu locken; nicht wundern, wenn es etwas dauert bis die Exception geworfen wird.
@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?
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?
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...
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()
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 ...
Man kann es mit PEP 8 auch übertreiben ...
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
``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 (former) Modvoice
Sicher, aber auf zwei Zeilen Code bringt das auch niemanden umLeonidas 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.

-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Natürlich nicht, aber als jemand der sich mehr als einmal gewundert hat warum Funktionen auf einmal nicht mehr funktionieren wird man vorsichtigerlunar hat geschrieben:Sicher, aber auf zwei Zeilen Code bringt das auch niemanden um

My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
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:
Hier wird gleich str und file überschrieben
. Und das auch mit anderen builtins an vielen anderen Stellen.
MFG HerrHagen
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()

MFG HerrHagen
@lunarlunar 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.
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.
für die suchenden: in diesem post http://www.python-forum.de/topic-18526.html habe ich das ganze file interface umgesetz