我过去常常打开与当前运行的Python脚本在同一目录下的文件,只需使用如下命令:

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

然而,我发现当在Windows中双击该脚本时,它会试图从错误的目录打开文件。

从那以后,我一直使用表单的命令

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

每当我想打开一个文件。这适用于我的特定用法,但我不确定sys。路径[0]可能在其他用例中失败。

所以我的问题是:打开与当前运行的Python脚本位于同一目录下的文件的最佳和最可靠的方法是什么?

以下是我目前所了解到的情况:

os.getcwd() and os.path.abspath('') return the "current working directory", not the script directory. os.path.dirname(sys.argv[0]) and os.path.dirname(__file__) return the path used to call the script, which may be relative or even blank (if the script is in the cwd). Also, __file__ does not exist when the script is run in IDLE or PythonWin. sys.path[0] and os.path.abspath(os.path.dirname(sys.argv[0])) seem to return the script directory. I'm not sure if there's any difference between these two.

编辑:

我刚刚意识到,我想做的事情应该更好地描述为“在包含模块的同一目录中打开一个文件”。换句话说,如果我导入了一个我在另一个目录下编写的模块,而该模块打开了一个文件,我希望它在模块的目录下查找该文件。我不认为我发现的任何东西都能做到这一点……


当前回答

在Python 3.4中,添加了pathlib模块,下面的代码将可靠地打开与当前脚本相同目录下的文件:

from pathlib import Path

p = Path(__file__).with_name('file.txt')
with p.open('r') as f:
    print(f.read())

如果你需要文件路径作为一个字符串来使用一些类似开放的API,你可以使用absolute():

p = Path(__file__).with_name('file.txt')
filename = p.absolute()

注意:Python reps,如运行Python命令而不带目标或ipython,不会公开__file__。

其他回答

我是这么做的

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。路径,特别是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

如你所见,file总是给你运行它的python文件,而sys。Argv[0]给出了你总是从解释器运行的文件。根据你的需要,你需要选择一个最适合你的需求。

我通常使用以下方法。它适用于测试,也可能适用于其他用例。

使用open(os.path.join(os.path.dirname(__file__), 'some_file.txt'), 'r')作为f:

建议登录https://stackoverflow.com/questions/10174211/how-to-make-an-always-relative-to-current-module-file-path


因为我在尝试使用__file__或sys。我是这样做的:

from inspect import getfile
from pathlib import Path


script_path = getfile(lambda: None)
print(script_path)
parent_path = Path(script_path).parent
print(parent_path)

with open(parent_path/'Some file.txt', 'r') as obFile:
    print(obFile.read())

我会这样做:

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]。然后它检查该文件是否实际存在,然后使用上下文管理器打开它,这样您就不必记得在文件句柄上调用close。恕我直言,从长远来看,这样做会为你省去很多痛苦。

在Python 3.4中,添加了pathlib模块,下面的代码将可靠地打开与当前脚本相同目录下的文件:

from pathlib import Path

p = Path(__file__).with_name('file.txt')
with p.open('r') as f:
    print(f.read())

如果你需要文件路径作为一个字符串来使用一些类似开放的API,你可以使用absolute():

p = Path(__file__).with_name('file.txt')
filename = p.absolute()

注意:Python reps,如运行Python命令而不带目标或ipython,不会公开__file__。