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

发布于 2024-09-29 12:59:39 字数 998 浏览 0 评论 0原文

我曾经通过简单地使用以下命令来打开与当前运行的 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])) 似乎返回脚本目录。我不确定这两者之间是否有任何区别。

编辑:

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

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...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

养猫人 2024-10-06 12:59:39

我总是使用:

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

join() 调用预先考虑当前工作目录,但文档说如果某个路径是绝对路径,则其左侧的所有其他路径都会被删除。因此,当 dirname(__file__) 返回绝对路径时,getcwd() 将被删除。

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

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

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

我使用它来将资源与 Windows 和 Linux 上的多个 Django 应用程序捆绑在一起,它的工作方式就像一个魅力!

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!

当梦初醒 2024-10-06 12:59:39

在 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 的 API,则可以使用 获取它Absolute()

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

注意:Python REPL,例如在没有目标或 ipythonpython 命令code> 不要公开 __file__

On Python 3.4, the pathlib module was added, and the following code will reliably open a file in the same directory as the current script:

from pathlib import Path

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

If you instead need the file path as a string for some open-like API, you can get it using absolute():

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

NOTE: Python REPLs such as running the python command without a target or ipython do not expose __file__.

醉梦枕江山 2024-10-06 12:59:39

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

那么请注意!

To quote from the Python documentation:

As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter. If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input), path[0] is the empty string, which directs Python to search modules in the current directory first. Notice that the script directory is inserted before the entries inserted as a result of PYTHONPATH.

If you are running the script from the terminal, sys.path[0] is what you are looking for.

However, if you have:

barpath/bar.py
    import foopath.foo

foopath/foo.py
    print sys.path[0]  # you get barpath

So watch out!

梦纸 2024-10-06 12:59:39

好的,这就是我所做的

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

Ok here is what I do

sys.argv is always what you type into the terminal or use as the file path when executing it with python.exe or pythonw.exe

For example you can run the file text.py several ways, they each give you a different answer they always give you the path that python was typed.

    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

Ok so know you can get the file name, great big deal, now to get the application directory you can know use os.path, specifically abspath and dirname

    import sys, os
    print os.path.dirname(os.path.abspath(sys.argv[0]))

That will output this:

   C:\Documents and Settings\Admin\

it will always output this no matter if you type python test.py or python "C:\Documents and Settings\Admin\test.py"

The problem with using __file__
Consider these two files
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]

Output of "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

Output of "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

So as you can see file gives you always the python file it is being run from, where as sys.argv[0] gives you the file that you ran from the interpreter always. Depending on your needs you will need to choose which one best fits your needs.

不乱于心 2024-10-06 12:59:39

我常用的有以下几种。它适用于测试,也可能适用于其他用例。

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

这个答案在 https://stackoverflow.com/questions/ 10174211/如何制作始终相对于当前模块文件路径

I commonly use the following. It works for testing and probably other use cases as well.

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

This answer is recommended in https://stackoverflow.com/questions/10174211/how-to-make-an-always-relative-to-current-module-file-path


假装爱人 2024-10-06 12:59:39

您可以尝试这种简单的方法吗:

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

Can you try this simple approach just like this:

    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()
你对谁都笑 2024-10-06 12:59:39

因为我在尝试使用 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())

Because I get an error trying to use __file__ or sys.argv[0] from emacs I do it that way:

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())
暮光沉寂 2024-10-06 12:59:39

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

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

config.py 内部的内容:

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

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

After trying all of this solutions, I still had different problems. So what I found the simplest way was to create a python file: config.py, with a dictionary containing the file's absolute path and import it into the script.
something like

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

where config.py has inside:

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

It is not automatic but it is a good solution when you have to work in different directory or different machines.

请远离我 2024-10-06 12:59:39

我会这样做:

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

I'd do it this way:

from os.path import abspath, exists

f_path = abspath("fooabar.txt")

if exists(f_path):
    with open(f_path) as f:
        print f.read()

The above code builds an absolute path to the file using abspath and is equivalent to using normpath(join(os.getcwd(), path)) [that's from the pydocs]. It then checks if that file actually exists and then uses a context manager to open it so you don't have to remember to call close on the file handle. IMHO, doing it this way will save you a lot of pain in the long run.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文