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

时间:2010-10-30 19:05:53

标签: python directory

我曾经只使用像

这样的命令打开与当前运行的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中)。此外,当脚本在IDLE或PythonWin中运行时,__file__不存在。

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

修改

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

7 个答案:

答案 0 :(得分:153)

我总是使用:

__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应用程序,它就像一个魅力!

答案 1 :(得分:30)

引用Python文档:

  

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

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

答案 2 :(得分:18)

好的,这就是我做的事情

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]为您提供始终从解释器运行的文件。根据您的需求,您需要选择最适合您需求的产品。

答案 3 :(得分:1)

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

from pathlib import Path

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

如果需要,还可以使用parent.absolute()来获取目录值作为字符串:

p = Path(__file__)
dir_abs = p.parent.absolute()  # Will return the executable directory absolute path

答案 4 :(得分:0)

我这样做:

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

答案 5 :(得分:0)

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

with open(os.path.join(os.path.dirname(__file__), 'some_file.txt'), 'r') as f:

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


中推荐此答案

答案 6 :(得分:-1)

在尝试了所有这些解决方案后,我仍然遇到了不同的问题。所以我发现最简单的方法是创建一个 python 文件:config.py,其中包含一个包含文件绝对路径的字典并将其导入到脚本中。 类似的东西

import config as cfg 
import pandas as pd 
pd.read_csv(cfg.paths['myfilepath'])

config.py 所在的位置:

paths = {'myfilepath': 'home/docs/...'}

它不是自动的,但是当您必须在不同的目录或不同的机器上工作时,它是一个很好的解决方案。