Как надежно открыть файл в том же каталоге, что и Python script
Я использовал для открытия файлов, которые были в том же каталоге, что и текущий Python script, просто используя команду типа
open("Some file.txt", "r")
Однако я обнаружил, что когда script был запущен в Windows, дважды щелкнув его, он попытается открыть файл из неправильного каталога.
С тех пор я использовал команду формы
open(os.path.join(sys.path[0], "Some file.txt"), "r")
всякий раз, когда я хотел открыть файл. Это работает для моего конкретного использования, но я не уверен, что sys.path[0]
может потерпеть неудачу в некоторых других случаях использования.
Итак, мой вопрос: какой лучший и надежный способ открыть файл, который находится в том же каталоге, что и текущий Python script?
Вот что мне удалось выяснить до сих пор:
-
os.getcwd()
и os.path.abspath('')
верните "текущий рабочий каталог", а не каталог script.
-
os.path.dirname(sys.argv[0])
и os.path.dirname(__file__)
вернуть путь, используемый для вызова script, который может быть относительным или даже пустым (если script находится в cwd). Кроме того, __file__
не существует, когда script выполняется в IDLE или PythonWin.
-
sys.path[0]
и os.path.abspath(os.path.dirname(sys.argv[0]))
, похоже, возвращают каталог script. Я не уверен, есть ли разница между этими двумя.
Edit:
Я просто понял, что то, что я хочу сделать, лучше описать как "открыть файл в том же каталоге, что и содержащий модуль". Другими словами, если я импортирую модуль, я написал, что в другом каталоге, и этот модуль открывает файл, я хочу, чтобы он искал файл в каталоге модуля. Я не думаю, что все, что я нашел, может это сделать...
Ответы
Ответ 1
Я всегда использую:
__location__ = os.path.realpath(
os.path.join(os.getcwd(), os.path.dirname(__file__)))
Вызов join()
добавляет текущий рабочий каталог, но в документации говорится, что если какой-то путь является абсолютным, все остальные пути, оставшиеся от него, будут удалены. Поэтому getcwd()
отбрасывается, когда dirname(__file__)
возвращает абсолютный путь.
Кроме того, вызов realpath
разрешает символические ссылки, если они найдены. Это позволяет избежать проблем при развертывании с помощью setuptools в системах Linux (сценарии символически привязаны к /usr/bin/
- по крайней мере, на Debian).
Для открытия файлов в одной папке вы можете использовать следующее:
f = open(os.path.join(__location__, 'bundled-resource.jpg'));
# ...
Я использую это для объединения ресурсов с несколькими приложениями Django как в Windows, так и в Linux, и это работает как шарм!
Ответ 2
Для цитирования из документации Python:
Как инициализировано при запуске программы, первым элементом этого списка является путь [0], это каталог, содержащий script, который использовался для вызова интерпретатора Python. Если каталог script недоступен (например, если интерпретатор вызывается интерактивно или если script считывается со стандартного ввода), путь [0] - это пустая строка, которая направляет Python на поиск модулей в текущем каталоге сначала, Обратите внимание, что каталог script вставлен перед вставками в результате PYTHONPATH.
sys.path [0] - это то, что вы ищете.
Ответ 3
Хорошо, вот что я делаю
sys.argv - это то, что вы вводите в терминал или используете в качестве пути к файлу при выполнении его с помощью python.exe или pythonw.exe
Например, вы можете запустить файл text.py несколькими способами, каждый из них даст вам другой ответ, который всегда дает вам путь, на который был набран python.
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
Хорошо, так что знайте, что вы можете получить имя файла, большое дело, теперь, чтобы получить каталог приложений, который вы можете знать, используйте os.path, а именно abspath и dirname
import sys, os
print os.path.dirname(os.path.abspath(sys.argv[0]))
Это выведет это:
C:\Documents and Settings\Admin\
он всегда выводит это независимо от того, набираете ли вы python test.py или python "C:\Documents and Settings\Admin\test.py"
Проблема с использованием __file __
Рассмотрим эти два файла
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]
Вывод "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
Вывод "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
Итак, вы можете видеть, что файл дает вам всегда исполняемый файл python, где sys.argv [0] предоставляет вам файл, который вы всегда запускали из интерпретатора. В зависимости от ваших потребностей вам нужно будет выбрать, какой из них лучше всего подходит вашим потребностям.
Ответ 4
Я бы сделал это следующим образом:
from os.path import abspath, exists
f_path = abspath("fooabar.txt")
if exists(f_path):
with open(f_path) as f:
print f.read()
Вышеприведенный код строит абсолютный путь к файлу с помощью abspath и эквивалентен использованию normpath(join(os.getcwd(), path))
[, который из pydocs], Затем он проверяет, действительно ли этот файл exists, а затем использует диспетчер контекста, чтобы открыть его, чтобы вам не приходилось задерживать вызов дескриптор файла. ИМХО, делая это таким образом, в долгосрочной перспективе сэкономит вам много боли.