2010-10-30 12 views
90

Ich benutzen Dateien zu öffnen, die als den aktuell laufenden Python-Skript im selben Verzeichnis waren einfach durch einen Befehl wieWie zuverlässig eine Datei im selben Verzeichnis wie ein Python-Skript öffnet

open("Some file.txt", "r") 

jedoch mit, ich Wenn das Skript in Windows ausgeführt wurde, indem es doppelt geklickt wurde, wurde versucht, die Datei aus dem falschen Verzeichnis zu öffnen.

Seitdem habe ich einen Befehl der Form verwendet

open(os.path.join(sys.path[0], "Some file.txt"), "r") 

, wenn ich eine Datei öffnen wollte. Dies funktioniert für meine spezielle Verwendung, aber ich bin mir nicht sicher, ob sys.path[0] in einem anderen Anwendungsfall fehlschlagen kann.

Meine Frage ist also: Was ist die beste und zuverlässigste Möglichkeit, eine Datei zu öffnen, die sich im selben Verzeichnis befindet wie das aktuell ausgeführte Python-Skript?

Hier ist, was ich in der Lage gewesen, so weit, um herauszufinden:

  • os.getcwd() und os.path.abspath('') das „aktuelle Arbeitsverzeichnis“ zurückzukehren, nicht das Skriptverzeichnis.

  • os.path.dirname(sys.argv[0]) und os.path.dirname(__file__) geben Sie den Pfad zum Aufruf des Skripts zurück, der relativ oder sogar leer sein kann (wenn sich das Skript in der cwd befindet). Außerdem ist __file__ nicht vorhanden, wenn das Skript in IDLE oder PythonWin ausgeführt wird.

  • sys.path[0] und os.path.abspath(os.path.dirname(sys.argv[0])) scheinen das Skriptverzeichnis zurückzugeben. Ich bin mir nicht sicher, ob es einen Unterschied zwischen diesen beiden gibt.

Edit:

Ich habe erkannt, dass das, was ich besser machen will als „eine Datei als Modul enthält, in demselben Verzeichnis öffnen“ würde beschrieben. Mit anderen Worten, wenn ich ein Modul, das ich geschrieben habe, in ein anderes Verzeichnis importiere, und dieses Modul eine Datei öffnet, möchte ich, dass es nach der Datei im Verzeichnis des Moduls sucht. Ich glaube nicht, alles, was ich gefunden habe in der Lage ist, das zu tun ...

Antwort

108

ich immer wie folgt:

__location__ = os.path.realpath(
    os.path.join(os.getcwd(), os.path.dirname(__file__))) 

Der join() Aufruf das aktuelle Arbeitsverzeichnis prepends, aber die Dokumentation sagt, dass, wenn irgend Weg ist absolut, alle anderen verbleibenden Pfade sind verworfen. Daher wird getcwd() gelöscht, wenn dirname(__file__) einen absoluten Pfad zurückgibt.

Auch der realpath Aufruf löst symbolische Verbindungen, wenn solche gefunden werden. Dies verhindert Probleme bei der Bereitstellung mit setuptools auf Linux-Systemen (Skripte sind mit /usr/bin/ - zumindest auf Debian) symlinked.

Sie können die Installation der folgenden Dateien im selben Ordner zu öffnen:

f = open(os.path.join(__location__, 'bundled-resource.jpg')); 
# ... 

Ich benutze diese auf Windows und Linux-Ressourcen mit mehreren Django-Anwendung zu bündeln und es wirkt wie ein Zauber!

+2

Wenn '__file__' nicht verwendet werden kann, verwenden Sie' sys.argv [0] 'anstelle von' dirname (__ file __) '. Der Rest sollte wie erwartet funktionieren. Ich benutze gerne "__file__", weil 'sys.argv [0]' im Bibliothekscode möglicherweise gar nicht auf Ihren Code zeigt, besonders wenn Sie über ein Drittanbieter-Skript importiert werden. –

+1

Das Problem dabei ist, es wird variieren, wenn Sie die Datei direkt aus dem Unterbrecher ausgeführt wird oder wenn es importiert wird. Siehe meine Antwort für die Unterschiede zwischen __file__ und sys.argv [0] – Zimm3r

+0

So ist es richtig zu sagen, dass die in Zimm3r Antwort beschrieben Variation ist mit "realpath (join (getcwd(), dirname (__ file__))" als hier beschrieben? – pianoJames

4

Ich würde es auf diese Weise tun:

from os.path import abspath, exists 

f_path = abspath("fooabar.txt") 

if exists(f_path): 
    with open(f_path) as f: 
     print f.read() 

Der obige Code baut einen absoluten Pfad zur Datei mit normpath(join(os.getcwd(), path))abspath und ist mit äquivalent [das ist von dem pydocs]. Es prüft dann, ob diese Datei tatsächlich exists ist, und verwendet dann einen Kontextmanager, um es zu öffnen, damit Sie nicht daran denken müssen, das Dateihandle zu schließen. IMHO, wird es Ihnen auf lange Sicht viel Schmerz ersparen.

+0

Dies beantwortet die Frage des Posters nicht. dln385 hat ausdrücklich gesagt, dass 'os.path.abspath' keine Pfade zu Dateien im selben Ordner wie das Skript auflöst, wenn sich das Skript nicht im aktuellen Verzeichnis befindet. –

+0

AH! Ich nahm an, dass der Benutzer dieses Skript im selben Verzeichnis wie die Datei, die sie lesen wollten, * NOT * im Modulverzeichnis von etwas in ihrem PYTHONPATH ausführt. Das wird mich lehren, Annahmen zu machen ... – dcolish

12

Ok hier ist, was ich tun

sys.argv ist immer das, was Sie in das Terminal eingeben oder als Dateipfad verwenden, wenn es mit python.exe oder pythonw.exe Ausführung

Zum Beispiel können Sie Führen Sie die Datei text.py mehrere Möglichkeiten, sie geben Ihnen jeweils eine andere Antwort sie geben Ihnen immer den Pfad, dass Python eingegeben wurde.

C:\Documents and Settings\Admin>python test.py 
    sys.argv[0]: test.py 
    C:\Documents and Settings\Admin>python "C:\Documents and Settings\Admin\test.py" 
    sys.argv[0]: C:\Documents and Settings\Admin\test.py 

Ok wissen, damit Sie die Dateinamen, große große Sache zu bekommen, jetzt das Anwendungsverzeichnis erhalten Sie Verwendung os.path wissen können, speziell abspath und dirname

import sys, os 
    print os.path.dirname(os.path.abspath(sys.argv[0])) 

Das wird Ausgang dieses :

C:\Documents and Settings\Admin\ 

es wird dies unabhängig davon, ob Sie python test.py oder python geben immer Ausgang "C: \ Dokumente und Einstellungen \ Admin \ test.py"

Das Problem bei der Verwendung __file__ Betrachten Sie diese zwei Dateien test.py

import sys 
import os 

def paths(): 
     print "__file__: %s" % __file__ 
     print "sys.argv: %s" % sys.argv[0] 

     a_f = os.path.abspath(__file__) 
     a_s = os.path.abspath(sys.argv[0]) 

     print "abs __file__: %s" % a_f 
     print "abs sys.argv: %s" % a_s 

if __name__ == "__main__": 
    paths() 

import_test.py

import test 
import sys 

test.paths() 

print "--------" 
print __file__ 
print sys.argv[0] 

Ausgabe von "Python test.py"

C:\Documents and Settings\Admin>python test.py 
__file__: test.py 
sys.argv: test.py 
abs __file__: C:\Documents and Settings\Admin\test.py 
abs sys.argv: C:\Documents and Settings\Admin\test.py 

Ausgabe von "python test_import.py"

C:\Documents and Settings\Admin>python test_import.py 
__file__: C:\Documents and Settings\Admin\test.pyc 
sys.argv: test_import.py 
abs __file__: C:\Documents and Settings\Admin\test.pyc 
abs sys.argv: C:\Documents and Settings\Admin\test_import.py 
-------- 
test_import.py 
test_import.py 

So wie Sie sehen können Datei gibt Ihnen immer die Python-Datei aus ausgeführt wird, wo als sys.argv [0] gibt Ihnen die Datei, die Sie aus dem Interpreter lief immer. Abhängig von Ihren Bedürfnissen müssen Sie wählen, welches am besten zu Ihren Bedürfnissen passt.

+1

Dies ist ein aufwendiger Beweis, dass die Implementierung die Dokumentation widerspiegelt. '__file__' soll *" immer den Pfad zur aktuellen Datei angeben ", und' sys.argv [0] 'soll *" immer den Pfad des Skriptes angeben, das den Prozess initiiert hat ". In jedem Fall liefert die Verwendung von '__file__' in dem Skript, das aufgerufen wird, immer genaue Ergebnisse. –

+0

Ich habe nur darauf hingewiesen und etwas gegeben, um es zu zeigen. – Zimm3r

+0

Wenn Sie den Verweis auf "__file__" auf der obersten Ebene des Skripts haben, wird es wie erwartet funktionieren. –

18

aus der Python-Dokumentation zitieren:

Wie beim Programmstart initialisiert, das erste Element dieser Liste, Pfad [0], ist das Verzeichnis, das das Skript enthält, das verwendet wurde, die Python-Interpreter aufgerufen werden kann. Wenn das Skriptverzeichnis nicht verfügbar ist (z. B. wenn der Interpreter interaktiv aufgerufen wird oder wenn das Skript von der Standardeingabe gelesen wird), ist Pfad [0] die leere Zeichenfolge, die Python anweist, zunächst Module im aktuellen Verzeichnis zu suchen. Beachten Sie, dass das Skriptverzeichnis vor den Einträgen eingefügt wird, die als Ergebnis von PYTHONPATH eingefügt wurden.

sys.path [0] ist was Sie suchen.

+1

Und für den vollständigen Pfad der Datei: 'os.path.join (sys.path [0], 'einige file.txt')'. Das sollte Leerzeichen und Schrägstriche auf allen Systemen korrekt behandeln. – P1h3r1e3d13

+0

Diese Antwort auf die erste Frage, nicht die nach der EDIT. – mcoolive

Verwandte Themen