Ich habe einen Pfad (einschließlich Verzeichnis und Dateiname).
Ich muss testen, ob der Dateiname gültig ist, z. B. ob das Dateisystem es mir ermöglicht, eine Datei mit einem solchen Namen zu erstellen.
Der Dateiname enthält einige Unicode-Zeichen .
Es ist sicher anzunehmen, dass das Verzeichnissegment des Pfads gültig und zugänglich ist ( ich habe versucht, die Frage allgemeiner anwendbar zu machen, und anscheinend bin ich zu weit gegangen ).
Ich möchte sehr gerne nichts entkommen müssen, wenn ich nicht muss .
Ich würde einige der Beispielzeichen posten, mit denen ich es zu tun habe, aber anscheinend werden sie automatisch vom Stapelaustauschsystem entfernt. Wie auch immer, ich möchte Standard-Unicode-Entitäten wie beibehalten ö
und nur Dinge maskieren, die in einem Dateinamen ungültig sind.
Hier ist der Haken. Möglicherweise befindet sich bereits eine Datei am Ziel des Pfads (oder auch nicht). Ich muss diese Datei behalten, wenn sie existiert, und keine Datei erstellen, wenn sie nicht existiert.
Grundsätzlich mag ich prüfen , ob ich könnte auf einen Pfad schreiben , ohne tatsächlich zu öffnen den Weg für das Schreiben (und die automatische Erstellung der Datei / Datei clobbering dass in der Regel bringt).
So wie:
try:
open(filename, 'w')
except OSError:
# handle error here
Ist nicht akzeptabel, da dadurch die vorhandene Datei überschrieben wird, die ich nicht berühren möchte (falls vorhanden), oder die Datei erstellt wird, wenn dies nicht der Fall ist.
Ich weiß, dass ich tun kann:
if not os.access(filePath, os.W_OK):
try:
open(filePath, 'w').close()
os.unlink(filePath)
except OSError:
# handle error here
Aber das wird die Datei an der erstellenfilePath
, die ich dann müsste os.unlink
.
Am Ende scheint es, als würde man 6 oder 7 Zeilen ausgeben, um etwas zu tun, das so einfach os.isvalidpath(filePath)
oder ähnlich sein sollte.
Abgesehen davon muss dies unter (mindestens) Windows und MacOS ausgeführt werden, daher möchte ich plattformspezifische Dinge vermeiden.
``
quelle
Antworten:
tl; dr
Rufen Sie die
is_path_exists_or_creatable()
unten definierte Funktion auf.Streng Python 3. Genau so rollen wir.
Eine Geschichte von zwei Fragen
Die Frage "Wie teste ich die Gültigkeit von Pfadnamen und bei gültigen Pfadnamen die Existenz oder Schreibbarkeit dieser Pfade?" ist eindeutig zwei getrennte Fragen. Beide sind interessant und haben hier keine wirklich zufriedenstellende Antwort erhalten ... oder irgendwo , wo ich sie finden könnte.
vikki ‚s Antwort haue wahrscheinlich in der Nähe, hat aber die bemerkenswerten Nachteile:
Wir werden das alles reparieren.
Frage 0: Was ist wieder die Gültigkeit von Pfadnamen?
Bevor wir unsere zerbrechlichen Fleischanzüge in die von Python durchsetzten Moshpits des Schmerzes schleudern, sollten wir wahrscheinlich definieren, was wir unter "Gültigkeit von Pfadnamen" verstehen. Was genau definiert Gültigkeit?
Mit "Gültigkeit von Pfadnamen" ist die syntaktische Korrektheit eines Pfadnamens in Bezug auf das Root-Dateisystem des aktuellen Systems gemeint - unabhängig davon, ob dieser Pfad oder dessen übergeordnete Verzeichnisse physisch vorhanden sind. Ein Pfadname ist unter dieser Definition syntaktisch korrekt, wenn er alle syntaktischen Anforderungen des Root-Dateisystems erfüllt.
Mit "Root-Dateisystem" meinen wir:
/
) bereitgestellt .%HOMEDRIVE%
dem Laufwerksbuchstaben mit Doppelpunkt versehen, der die aktuelle Windows-Installation enthält (normalerweise, aber nicht unbedingtC:
).Die Bedeutung von "syntaktischer Korrektheit" hängt wiederum von der Art des Root-Dateisystems ab. Für
ext4
(und die meisten, aber nicht alle POSIX-kompatiblen) Dateisysteme ist ein Pfadname genau dann syntaktisch korrekt, wenn dieser Pfadname:\x00
in Python). Dies ist eine wichtige Voraussetzung für alle POSIX-kompatiblen Dateisysteme.'a'*256
in Python). Eine Pfadkomponente ist eine längste Teilkette eines Pfadnamen NO/
Charakter (zBbergtatt
,ind
,i
, undfjeldkamrene
in dem Pfadnamen/bergtatt/ind/i/fjeldkamrene
).Syntaktische Korrektheit. Root-Dateisystem. Das ist es.
Frage 1: Wie sollen wir jetzt die Gültigkeit von Pfadnamen tun?
Das Überprüfen von Pfadnamen in Python ist überraschenderweise nicht intuitiv. Ich bin hier fest mit Fake Name einverstanden : Das offizielle
os.path
Paket sollte eine sofort einsatzbereite Lösung dafür bieten. Aus unbekannten (und wahrscheinlich nicht zwingenden) Gründen ist dies nicht der Fall. Glücklicherweise ist Ihre eigene Ad-hoc - Lösung Abrollen nicht , dass stechende ...OK, das ist es tatsächlich. Es ist haarig; es ist fies; es gluckst wahrscheinlich, wenn es knurrt und kichert, wenn es glüht. Aber was wirst du tun? Nuthin '.
Wir werden bald in den radioaktiven Abgrund des Low-Level-Codes abtauchen. Aber zuerst sprechen wir über High-Level-Shop. Der Standard
os.stat()
und dieos.lstat()
Funktionen lösen die folgenden Ausnahmen aus, wenn ungültige Pfadnamen übergeben werden:FileNotFoundError
.WindowsError
derenwinerror
Attribut123
(dhERROR_INVALID_NAME
) ist.'\x00'
) enthalten, Instanzen vonTypeError
.OSError
deren Instanzenerrcode
Folgendes sind:errno.ERANGE
. (Dies scheint ein Fehler auf Betriebssystemebene zu sein, der auch als "selektive Interpretation" des POSIX-Standards bezeichnet wird.)errno.ENAMETOOLONG
.Entscheidend ist, dass nur Pfadnamen in vorhandenen Verzeichnissen validiert werden können. Die Funktionen
os.stat()
undos.lstat()
lösen generischeFileNotFoundError
Ausnahmen aus, wenn übergebene Pfadnamen in nicht vorhandenen Verzeichnissen übergeben werden, unabhängig davon, ob diese Pfadnamen ungültig sind oder nicht. Die Existenz eines Verzeichnisses hat Vorrang vor der Ungültigkeit des Pfadnamens.Bedeutet dies, dass Pfadnamen, die sich in nicht vorhandenen Verzeichnissen befinden, nicht validierbar sind? Ja - es sei denn, wir ändern diese Pfadnamen so, dass sie sich in vorhandenen Verzeichnissen befinden. Ist das aber überhaupt sicher machbar? Sollte das Ändern eines Pfadnamens nicht verhindern, dass wir den ursprünglichen Pfadnamen überprüfen?
Um diese Frage zu beantworten, erinnern Sie sich von oben daran, dass syntaktisch korrekte Pfadnamen im
ext4
Dateisystem keine Pfadkomponenten (A) enthalten, die Null-Bytes oder (B) mehr als 255 Bytes enthalten. Daher ist einext4
Pfadname nur dann gültig, wenn alle Pfadkomponenten in diesem Pfadnamen gültig sind. Dies gilt für die meisten interessierenden realen Dateisysteme .Hilft uns diese pedantische Einsicht tatsächlich? Ja. Es reduziert das größere Problem der Validierung des vollständigen Pfadnamens auf einen Schlag auf das kleinere Problem der Validierung aller Pfadkomponenten in diesem Pfadnamen. Jeder beliebige Pfadname kann plattformübergreifend überprüft werden (unabhängig davon, ob sich dieser Pfadname in einem vorhandenen Verzeichnis befindet oder nicht), indem der folgende Algorithmus befolgt wird:
/troldskog/faren/vild
in die Liste['', 'troldskog', 'faren', 'vild']
)./troldskog
. B. ).os.stat()
oder weiteros.lstat()
. Wenn dieser Pfadname und damit diese Komponente ungültig ist, löst dieser Aufruf garantiert eine Ausnahme aus, die den Typ der Ungültigkeit und nicht eine generischeFileNotFoundError
Ausnahme aufdeckt . Warum? Weil sich dieser Pfadname in einem vorhandenen Verzeichnis befindet. (Zirkuläre Logik ist zirkulär.)Gibt es ein garantiertes Verzeichnis? Ja, aber normalerweise nur eines: das oberste Verzeichnis des Root-Dateisystems (wie oben definiert).
Das Übergeben von Pfadnamen, die sich in einem anderen Verzeichnis befinden (und daher nicht garantiert existieren), an die Rennbedingungen
os.stat()
oderos.lstat()
lädt zu Rennbedingungen ein, selbst wenn dieses Verzeichnis zuvor auf Existenz getestet wurde. Warum? Weil externe Prozesse nicht daran gehindert werden können, dieses Verzeichnis gleichzeitig zu entfernen, nachdem dieser Test durchgeführt wurde, aber bevor dieser Pfadname anos.stat()
oder übergeben wirdos.lstat()
. Entfessle die Hunde des wahnsinnigen Wahnsinns!Der obige Ansatz hat auch einen erheblichen Nebeneffekt: Sicherheit. (Ist das nicht das schön?) Im Einzelnen:
Der obige Ansatz vermeidet dies, indem nur die Pfadkomponenten eines Pfadnamens anhand des Stammverzeichnisses des Stammdateisystems überprüft werden. (Wenn selbst das veraltet, langsam oder unzugänglich ist, haben Sie größere Probleme als die Überprüfung des Pfadnamens.)
Hat verloren? Toll. Lass uns anfangen. (Python 3 angenommen. Siehe "Was ist fragile Hoffnung für 300, Leycec ?")
Getan. Schielen Sie nicht auf diesen Code. ( Es beißt. )
Frage 2: Möglicherweise ungültige Existenz oder Erstellbarkeit von Pfadnamen, was?
Das Testen der Existenz oder Erstellbarkeit möglicherweise ungültiger Pfadnamen ist angesichts der obigen Lösung meist trivial. Der kleine Schlüssel hier ist, die zuvor definierte Funktion aufzurufen, bevor der übergebene Pfad getestet wird:
Fertig und fertig. Außer nicht ganz.
Frage 3: Möglicherweise ungültige Pfadnamen oder Beschreibbarkeit unter Windows
Es gibt eine Einschränkung. Natürlich gibt es das.
Wie die offizielle
os.access()
Dokumentation zulässt:Zu keiner Überraschung ist Windows hier der übliche Verdächtige. Dank der umfassenden Verwendung von Zugriffssteuerungslisten (Access Control Lists, ACL) in NTFS-Dateisystemen lässt sich das vereinfachte POSIX-Berechtigungsbitmodell nur schlecht auf die zugrunde liegende Windows-Realität abbilden. Obwohl dies (wohl) nicht Pythons Schuld ist, könnte es dennoch für Windows-kompatible Anwendungen von Belang sein.
Wenn Sie es sind, wird eine robustere Alternative gesucht. Wenn der übergebene Pfad nicht vorhanden ist, versuchen wir stattdessen, eine temporäre Datei zu erstellen, die garantiert sofort im übergeordneten Verzeichnis dieses Pfads gelöscht wird - ein portablerer (wenn auch teurer) Test der Erstellbarkeit:
Beachten Sie jedoch, dass auch dies möglicherweise nicht ausreicht.
Dank User Access Control (UAC), die ständig inimicable Windows Vista und alle nachfolgenden Iterationen davon liegt offensichtlich über Berechtigungen für Systemverzeichnisse betreffen. Wenn Nicht-Administrator - Benutzer in Dateien entweder den kanonischen zu erstellen versuchen
C:\Windows
oderC:\Windows\system32
Verzeichnissen, erlaubt UAC oberflächlich den Benutzer so zu tun , während tatsächlich alle erstellten Dateien in ein „Virtual Store“ Isolierung in dem Profil des Benutzers. (Wer hätte sich vorstellen können, dass die Täuschung von Benutzern langfristig schädliche Folgen haben würde?)Das ist verrückt. Das ist Windows.
Beweise es
Wagen wir es? Es ist Zeit, die oben genannten Tests zu testen.
Da NULL das einzige Zeichen ist, das in Pfadnamen auf UNIX-orientierten Dateisystemen verboten ist, nutzen wir dies, um die kalte, harte Wahrheit zu demonstrieren - und ignorieren Sie nicht ignorierbare Windows-Spielereien, die mich offen gesagt gleichermaßen langweilen und verärgern:
Jenseits der Vernunft. Jenseits des Schmerzes. Sie werden Bedenken hinsichtlich der Python-Portabilität finden.
quelle
is_
. Das ist mein Charakterfehler. Dennoch, gebührend bemerkt: Sie können nicht jedem gefallen, und manchmal können Sie niemandem gefallen. ;)Beachten Sie, dass
path.exists
dies aus mehr als nur einem Grund fehlschlagen kann,the file is not there
sodass Sie möglicherweise feinere Tests durchführen müssen, z. B. zu testen, ob das enthaltende Verzeichnis vorhanden ist, und so weiter.Nach meiner Diskussion mit dem OP stellte sich heraus, dass das Hauptproblem darin zu bestehen scheint, dass der Dateiname möglicherweise Zeichen enthält, die vom Dateisystem nicht zugelassen werden. Natürlich müssen sie entfernt werden, aber das OP möchte so viel menschliche Lesbarkeit aufrechterhalten, wie das Dateisystem zulässt.
Leider kenne ich keine gute Lösung dafür. In der Antwort von Cecil Curry wird das Problem jedoch genauer untersucht.
quelle
or can be created
Nun, das habe ich aus Ihrer Frage nicht gelesen. Das Lesen der Berechtigungen hängt in gewissem Maße von der Plattform ab.os.path.exists(filePath)
technisch Ausnahmen bei ungültigen Pfadnamen auslöst, müssten diese Ausnahmen explizit abgefangen und von anderen nicht verwandten Ausnahmen unterschieden werden. Darüber hinaus sind die gleichen Anruf kehrtFalse
nicht auf die bestehenden Pfade , auf die der aktuelle Benutzer nicht haben Berechtigungen gelesen. Kurz gesagt, Schlechtigkeit.Wie wäre es mit Python 3:
Mit der Option 'x' müssen wir uns auch keine Sorgen um die Rennbedingungen machen. Siehe Dokumentation hier .
Dies wird nun eine sehr kurzlebige temporäre Datei erstellen, wenn sie noch nicht existiert - es sei denn, der Name ist ungültig. Wenn Sie damit leben können, vereinfacht es die Dinge sehr.
quelle
öffnet die Datei oder gibt einen Fehler aus, wenn sie nicht vorhanden ist. Wenn ein Fehler vorliegt, können Sie versuchen, in den Pfad zu schreiben. Wenn dies nicht möglich ist, wird ein zweiter Fehler angezeigt
Schauen Sie sich hier auch die Berechtigungen für Windows an
quelle
tempfile.TemporaryFile()
, um die temporäre Datei automatisch zu zerstören, wenn sie den Gültigkeitsbereich verlässt.os.path.join
baue meine Wege mit , damit ich keine Probleme habe. Außerdem bin ich nicht wirklich mit Verzeichnis Erlaubnis Fragen. Ich habe Verzeichnis (und Dateiname) Name Probleme.filename
ungültige Zeichen enthält. Ich habe die Antwort bearbeitetVersuchen Sie
os.path.exists
dies, um nach dem Pfad zu suchen und zurückzukehren,True
falls vorhanden undFalse
wenn nicht.quelle