programa - Cómo abrir confiablemente un archivo en el mismo directorio que una secuencia de comandos de Python
ejemplos de python en arcgis (4)
Lo haría de esta manera:
from os.path import abspath, exists
f_path = abspath("fooabar.txt")
if exists(f_path):
with open(f_path) as f:
print f.read()
El código anterior construye una ruta absoluta al archivo usando abspath y es equivalente a usar normpath(join(os.getcwd(), path))
[que es de los pydocs]. Luego verifica si ese archivo realmente exists y luego utiliza un administrador de contexto para abrirlo, de modo que no tenga que recordar llamar para cerrar el identificador del archivo. En mi humilde opinión, hacerlo de esta manera le ahorrará mucho dolor en el largo plazo.
Solía abrir archivos que estaban en el mismo directorio que la secuencia de comandos en ejecución de Python, simplemente usando un comando como
open("Some file.txt", "r")
Sin embargo, descubrí que cuando la secuencia de comandos se ejecutaba en Windows haciendo doble clic en ella, intentaba abrir el archivo desde el directorio incorrecto.
Desde entonces he usado un comando de la forma
open(os.path.join(sys.path[0], "Some file.txt"), "r")
cada vez que quería abrir un archivo. Esto funciona para mi uso particular, pero no estoy seguro de si sys.path[0]
podría fallar en algún otro caso de uso.
Entonces mi pregunta es: ¿Cuál es la mejor y más confiable manera de abrir un archivo que está en el mismo directorio que el script de Python que se está ejecutando actualmente?
Esto es lo que he podido descifrar hasta ahora:
os.getcwd()
yos.path.abspath('''')
devuelven el "directorio de trabajo actual", no el directorio de scripts.os.path.dirname(sys.argv[0])
yos.path.dirname(__file__)
devuelven la ruta utilizada para llamar al script, que puede ser relativo o incluso en blanco (si el script está en el cwd). Además,__file__
no existe cuando el script se ejecuta en IDLE o PythonWin.sys.path[0]
yos.path.abspath(os.path.dirname(sys.argv[0]))
parecen devolver el directorio de scripts. No estoy seguro de si hay alguna diferencia entre estos dos.
Editar:
Me acabo de dar cuenta de que lo que quiero hacer se describiría mejor como "abrir un archivo en el mismo directorio que el módulo que lo contiene". En otras palabras, si importo un módulo, escribí que está en otro directorio, y ese módulo abre un archivo, quiero que busque el archivo en el directorio del módulo. No creo que nada de lo que he encontrado sea capaz de hacer eso ...
Ok aquí es lo que hago
sys.argv es siempre lo que escribe en el terminal o utiliza como ruta de archivo al ejecutarlo con python.exe o pythonw.exe
Por ejemplo, puede ejecutar el archivo text.py de varias maneras, cada una de ellas le da una respuesta diferente, siempre le dan la ruta de acceso que python fue tipada.
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, sé que puedes obtener el nombre del archivo, gran cosa, ahora para obtener el directorio de la aplicación que puedes conocer utiliza os.path, específicamente abspath y dirname
import sys, os
print os.path.dirname(os.path.abspath(sys.argv[0]))
Eso dará como resultado esto:
C:/Documents and Settings/Admin/
siempre dará como resultado esto no importa si escribe python test.py o python "C: / Documents and Settings / Admin / test.py"
El problema con el uso de __file__ Considere estos dos archivos 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]
Salida 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
Salida 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
Entonces, como puede ver, el archivo le proporciona siempre el archivo python desde donde se ejecuta, mientras que sys.argv [0] le proporciona siempre el archivo que ejecutó desde el intérprete. Según sus necesidades, deberá elegir cuál se ajusta mejor a sus necesidades.
Para citar de la documentación de Python:
Como se inicializó al inicio del programa, el primer elemento de esta lista, ruta [0], es el directorio que contiene la secuencia de comandos que se utilizó para invocar el intérprete de Python. Si el directorio de scripts no está disponible (por ejemplo, si el intérprete se invoca de forma interactiva o si el script se lee desde la entrada estándar), la ruta [0] es la cadena vacía que dirige Python para buscar módulos en el directorio actual primero. Observe que el directorio de scripts se inserta antes que las entradas insertadas como resultado de PYTHONPATH.
sys.path [0] es lo que estás buscando.
Yo siempre uso:
__location__ = os.path.realpath(
os.path.join(os.getcwd(), os.path.dirname(__file__)))
La llamada a join()
antepone el directorio de trabajo actual, pero la documentación dice que si alguna ruta es absoluta, se descartan todas las demás rutas restantes. Por lo tanto, se getcwd()
cuando dirname(__file__)
devuelve una ruta absoluta.
Además, la llamada realpath
resuelve enlaces simbólicos si se encuentra alguno. Esto evita problemas cuando se implementa con setuptools en sistemas Linux (los scripts se enlazan a /usr/bin/
- al menos en Debian).
Puede usar lo siguiente para abrir archivos en la misma carpeta:
f = open(os.path.join(__location__, ''bundled-resource.jpg''));
# ...
¡Utilizo esto para agrupar recursos con varias aplicaciones de Django en Windows y Linux y funciona como un encanto!