J'avais l'habitude d'ouvrir des fichiers qui se trouvaient dans le même répertoire que le script en cours d'exécution Python) en utilisant simplement une commande comme
open("Some file.txt", "r")
Cependant, j'ai découvert que lorsque le script était exécuté dans Windows en double-cliquant dessus, il tentait d'ouvrir le fichier à partir du mauvais répertoire.
Depuis lors, j'ai utilisé une commande de la forme
open(os.path.join(sys.path[0], "Some file.txt"), "r")
chaque fois que je voulais ouvrir un fichier. Cela fonctionne pour mon utilisation particulière, mais je ne suis pas sûr que sys.path[0]
Puisse échouer dans un autre cas d'utilisation.
Ma question est donc la suivante: quel est le moyen le plus sûr et le plus fiable d’ouvrir un fichier qui se trouve dans le même répertoire que le script Python en cours d’exécution)?
Voici ce que j'ai pu comprendre jusqu'à présent:
os.getcwd()
et os.path.abspath('')
renvoient le "répertoire de travail actuel", pas le répertoire du script.
os.path.dirname(sys.argv[0])
et os.path.dirname(__file__)
renvoient le chemin utilisé pour appeler le script, qui peut être relatif ou même vide (si le script est dans le cwd). De plus, __file__
N'existe pas lorsque le script est exécuté dans IDLE ou PythonWin.
sys.path[0]
Et os.path.abspath(os.path.dirname(sys.argv[0]))
semblent renvoyer le répertoire du script. Je ne suis pas sûr s'il y a une différence entre ces deux.
Edit:
Je viens de me rendre compte que ce que je veux faire serait mieux décrit comme "ouvre un fichier dans le même répertoire que le module contenant". En d'autres termes, si j'importe un module que j'ai écrit qui se trouve dans un autre répertoire et que ce module ouvre un fichier, je souhaite qu'il recherche le fichier dans le répertoire du module. Je ne pense pas que tout ce que j'ai trouvé puisse faire ça ...
J'utilise toujours:
__location__ = os.path.realpath(
os.path.join(os.getcwd(), os.path.dirname(__file__)))
L'appel join()
ajoute le répertoire de travail en cours, mais la documentation indique que si un chemin est absolu, tous les autres chemins sont supprimés. Par conséquent, getcwd()
est supprimé lorsque dirname(__file__)
renvoie un chemin absolu.
De plus, l'appel realpath
résout les liens symboliques, le cas échéant. Cela évite des problèmes lors du déploiement avec setuptools sur des systèmes Linux (les scripts sont liés symboliquement à /usr/bin/
- au moins sur Debian).
Vous pouvez utiliser les éléments suivants pour ouvrir des fichiers dans le même dossier:
f = open(os.path.join(__location__, 'bundled-resource.jpg'));
# ...
J'utilise ceci pour regrouper des ressources avec plusieurs Django applications sur Windows et Linux) et cela fonctionne à merveille!
Pour citer la Python):
Initialisé au démarrage du programme, le premier élément de cette liste, chemin [0], est le répertoire contenant le script utilisé pour appeler l'interprète Python. Si le répertoire de script n'est pas disponible ( Par exemple, si l'interpréteur est appelé de manière interactive ou si le script est lu à partir de l'entrée standard), chemin [0] est la chaîne vide qui indique à Python de rechercher d'abord les modules dans le répertoire en cours. Remarque le répertoire de script est inséré avant les entrées insérées à la suite de PYTHONPATH.
sys.path [0] est ce que vous recherchez.
Ok voici ce que je fais
sys.argv est toujours ce que vous tapez dans le terminal ou utilisez comme chemin de fichier lors de son exécution avec python.exe ou pythonw.exe
Par exemple, vous pouvez exécuter le fichier text.py de plusieurs manières, chacune vous donnant une réponse différente, elles vous donnent toujours le chemin que python a été tapé.
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, alors sachez que vous pouvez obtenir le nom du fichier, très gros, maintenant pour obtenir le répertoire de l'application, vous pouvez savoir utiliser os.path, en particulier abspath et dirname
import sys, os
print os.path.dirname(os.path.abspath(sys.argv[0]))
Cela produira ceci:
C:\Documents and Settings\Admin\
il le sortira toujours, peu importe si vous tapez python test.py ou python "C:\Documents et Paramètres\Admin\test.py"
Le problème avec l'utilisation de __file __ Considérez ces deux fichiers 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 __== "__main__":
paths()
import_test.py
import test
import sys
test.paths()
print "--------"
print __file__
print sys.argv[0]
Sortie de "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
Sortie de "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
Comme vous pouvez le voir, fichier vous donne toujours le fichier python à partir duquel il est exécuté, alors que sys.argv [0] vous donne le fichier à partir duquel vous avez exécuté toujours en fonction de vos besoins, vous devrez choisir celui qui correspond le mieux à vos besoins.
Je le ferais de cette façon:
from os.path import abspath, exists
f_path = abspath("fooabar.txt")
if exists(f_path):
with open(f_path) as f:
print f.read()
Le code ci-dessus crée un chemin absolu vers le fichier en utilisant abspath et équivaut à utiliser normpath(join(os.getcwd(), path))
[à partir des pydocs]. Il vérifie ensuite si ce fichier existe réellement existe et utilise ensuite un gestionnaire de contexte pour l'ouvrir, de sorte que vous n'ayez pas à vous rappeler d'appeler close sur le descripteur de fichier. IMHO, le faire de cette façon vous évitera beaucoup de douleur à long terme.