如何可靠地在与Python脚本相同的目录中打开文件


157

我曾经使用简单的命令打开与当前运行的Python脚本位于同一目录中的文件

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

但是,我发现双击该脚本在Windows中运行时,它将尝试从错误的目录中打开文件。

从那时起,我一直使用以下形式的命令

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

每当我想打开文件时。这适用于我的特定用法,但是我不确定sys.path[0]在其他用例中是否会失败。

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

到目前为止,这是我能够弄清楚的:

  • os.getcwd()os.path.abspath('')返回“当前工作目录”,而不是脚本目录。

  • os.path.dirname(sys.argv[0])os.path.dirname(__file__)返回用于调用脚本的路径,该路径可以是相对的,甚至可以是空白的(如果脚本在cwd中)。此外,__file__当脚本在IDLE或PythonWin中运行时不存在。

  • sys.path[0]os.path.abspath(os.path.dirname(sys.argv[0]))似乎返回脚本目录。我不确定这两者之间是否有任何区别。

编辑:

我只是意识到,我想做的更好的描述是“在与包含模块相同的目录中打开文件”。换句话说,如果我导入的模块写在另一个目录中,并且该模块打开一个文件,我希望它在模块目录中查找该文件。我认为我所发现的任何东西都无法做到这一点...

Answers:


199

我一直使用:

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

join()调用位于当前工作目录的前面,但是文档说如果某个路径是绝对路径,则将删除该路径中剩下的所有其他路径。因此,getcwd()dirname(__file__)返回绝对路径时会被丢弃。

同样,该realpath调用会解析符号链接(如果找到)。这样可以避免在Linux系统上使用setuptools进行部署时遇到麻烦(脚本/usr/bin/至少在Debian上是符号链接到的)。

您可以使用以下命令打开同一文件夹中的文件:

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

我用它来将资源与Windows和Linux上的多个Django应用程序捆绑在一起,它的工作原理很吸引人!


4
如果__file__无法使用,请使用sys.argv[0]代替dirname(__file__)。其余应按预期工作。我喜欢使用它,__file__因为在库代码中,sys.argv[0]可能根本不指向您的代码,尤其是通过某些第三方脚本导入时。
安德烈·卡隆(AndréCaron)2010年

1
问题在于,如果您正在运行的文件是直接来自中断器的文件,或者是从导入器中导入的文件,则它会有所不同。请参阅我的答案,了解文件和sys.argv [0] 之间的区别
Zimm3r 2010年

因此,可以说使用Zimm3r的答案中所述的变体是通过使用realpath( join( getcwd(), dirname(__file__) ))此处所述的方法解决的,这是正确的说法吗?
pianoJames

44

引用Python文档:

在程序启动时初始化后,该列表的第一项path [0]是包含用于调用Python解释器的脚本的目录。如果脚本目录不可用(例如,如果交互式调用解释器或从标准输入中读取脚本),则path [0]为空字符串,该字符串将引导Python首先搜索当前目录中的模块。请注意,由于PYTHONPATH的结果,在插入条目之前插入了脚本目录。

sys.path [0]是您要寻找的。


10
对于文件的完整路径:os.path.join(sys.path[0], 'some file.txt')。那应该在所有系统上正确处理空格和斜杠。
Jacktose

这是第一个问题的答案,而不是EDIT之后的问题。
mcoolive

22

好,这就是我要做的

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

因此,您可以看到file始终为您提供正在运行的python文件,而sys.argv [0]始终为您提供从解释器运行的文件。根据您的需求,您将需要选择最适合您的需求。


3
这充分证明了实现反映了文档。__file__假定为“总是给你的路径添加到当前文件”,并且sys.argv[0]认为为“总是给启动该进程脚本的路径”。无论如何,__file__在被调用的脚本中使用总是可以为您提供精确的结果。
安德烈·卡隆

如果您__file__在脚本的顶层具有对它的引用,则它将按预期运行。
马修·申克尔


-3

我会这样:

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了。恕我直言,从长远来看,这样做会为您省去很多痛苦。


这不能回答张贴者的问题。dln385特别表示,os.path.abspath如果脚本不在当前目录中,则不会解析与该脚本位于同一文件夹中的文件的路径。
安德烈·卡隆(AndréCaron)2010年

啊!我假设用户在与要读取的文件相同的目录中运行此脚本,而不是在PYTHONPATH中某个模块的目录中运行。那会教我做个假设...
dcolish

abspath将不起作用,因为python运行时无法使用这样的功能在OS文件系统上进行搜索。
akshat thakar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.