python 如何可靠地打开与当前运行的脚本位于同一目录中的文件

bz4sfanl  于 2022-12-02  发布在  Python
关注(0)|答案(9)|浏览(199)

I used to open files that were in the same directory as the currently running Python script by simply using a command like:

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

However, I discovered that when the script was run in Windows by double-clicking it, it would try to open the file from the wrong directory.
Since then I've used a command of the form

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

whenever I wanted to open a file. This works for my particular usage, but I'm not sure if sys.path[0] might fail in some other use case.
So my question is: What is the best and most reliable way to open a file that's in the same directory as the currently running Python script?
Here's what I've been able to figure out so far:

  • 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.
    Edit:

I just realized that what I want to do would be better described as "open a file in the same directory as the containing module". In other words, if I import a module I wrote that's in another directory, and that module opens a file, I want it to look for the file in the module's directory. I don't think anything I've found is able to do that...

vyswwuz2

vyswwuz21#

I always use:

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

The join() call prepends the current working directory, but the documentation says that if some path is absolute, all other paths left of it are dropped. Therefore, getcwd() is dropped when dirname(__file__) returns an absolute path.
Also, the realpath call resolves symbolic links if any are found. This avoids troubles when deploying with setuptools on Linux systems (scripts are symlinked to /usr/bin/ -- at least on Debian).
You may the use the following to open up files in the same folder:

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

I use this to bundle resources with several Django application on both Windows and Linux and it works like a charm!

i1icjdpr

i1icjdpr2#

在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())

如果您需要将文件路径作为某个类似open的API的字符串,则可以使用absolute()

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

dojqjjoe3#

引用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

所以要小心!

oxalkeyp

oxalkeyp4#

好吧我是这么做的
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_测试.py

import test
import sys

test.paths()

print "--------"
print __file__
print sys.argv[0]

“python www.example.com“的输出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]总是给你从解释器运行的文件。根据你的需要,你需要选择最适合你的文件。

velaa5lx

velaa5lx5#

我通常使用以下代码,它适用于测试,也可能适用于其他用例。
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
中使用此答案

c90pui9n

c90pui9n6#

你能不能试试这个简单的方法,就像这样:

import os

    my_local_file = os.path.join(os.path.dirname(__file__), 'some_file.txt')

    f = open(my_local_file,  "r")
    my_local_data = f.read()
dl5txlt9

dl5txlt97#

因为我在尝试使用emacs中的__file__sys.argv[0]时遇到错误,所以我这样做:

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())
4jb9z9bj

4jb9z9bj8#

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

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

其中config.py包含以下内容:

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

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

fhity93d

fhity93d9#

我会这么做:

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。恕我直言,这样做从长远来看会保存很多痛苦。

相关问题