如何可靠地打开与当前脚本在同一目录中的文件
我以前打开与当前运行的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__)
返回的是调用脚本时使用的路径,这个路径可能是相对路径,甚至可能是空的(如果脚本在当前工作目录下)。另外,当在IDLE或PythonWin中运行脚本时,__file__
是不存在的。sys.path[0]
和os.path.abspath(os.path.dirname(sys.argv[0]))
似乎返回的是脚本所在的目录。我不太确定这两者之间有没有区别。
补充:
我刚意识到,我想做的事情更准确的说法是“打开与包含模块在同一目录下的文件”。换句话说,如果我导入了一个在其他目录下的模块,而这个模块要打开一个文件,我希望它能在模块的目录里查找这个文件。我觉得我找到的任何方法都无法做到这一点……
9 个回答
根据Python的官方文档:
在程序启动时,这个列表的第一个项目,也就是path[0],是包含用来启动Python解释器的脚本的目录。如果脚本目录不可用(比如说你是直接在命令行中输入命令启动解释器,或者脚本是从标准输入读取的),那么path[0]就是一个空字符串,这样Python会优先在当前目录中查找模块。需要注意的是,脚本目录会被放在PYTHONPATH中其他条目之前。
如果你是从终端运行脚本,那么sys.path[0]
就是你需要关注的内容。
不过,如果你有:
barpath/bar.py
import foopath.foo
foopath/foo.py
print sys.path[0] # you get barpath
所以要小心哦!
在Python 3.4版本中,新增了一个叫做 pathlib
模块。使用下面的代码,你可以可靠地打开与当前脚本在同一个文件夹里的文件:
from pathlib import Path
p = Path(__file__).with_name('file.txt')
with p.open('r') as f:
print(f.read())
如果你需要将文件路径作为字符串来使用某些类似于 open
的功能,可以通过 absolute()
来获取:
p = Path(__file__).with_name('file.txt')
filename = p.absolute()
注意:像直接运行 python
命令或者使用 ipython
这样的Python交互环境是无法获取到 __file__
的。
我总是使用:
__location__ = os.path.realpath(
os.path.join(os.getcwd(), os.path.dirname(__file__)))
这里的 join()
方法会把当前工作目录加到路径前面,但文档上说如果某个路径是绝对路径,那么它左边的所有路径都会被丢掉。因此,当 dirname(__file__)
返回一个绝对路径时,getcwd()
就会被丢掉。
另外,realpath
方法会处理符号链接,如果找到的话。这可以避免在Linux系统上使用setuptools部署时出现问题(在Debian上,脚本会链接到 /usr/bin/
)。
你可以使用以下方法来打开同一文件夹中的文件:
f = open(os.path.join(__location__, 'bundled-resource.jpg'))
# ...
我用这个方法来打包多个Django应用的资源,在Windows和Linux上都能很好地工作!