简体   繁体   English

在python项目中使用相对路径读取文件

[英]Reading file using relative path in python project

Say I have a python project that is structured as follows:假设我有一个结构如下的python项目:

project
    /data
        test.csv
    /package
        __init__.py
        module.py
    main.py

__init__.py : __init__.py

from .module import test

module.py : module.py

import csv

with open("..data/test.csv") as f:
    test = [line for line in csv.reader(f)]

main.py : main.py

import package

print(package.test)

When I run main.py I get the following error:当我运行main.py ,出现以下错误:

 C:\Users\Patrick\Desktop\project>python main.py
Traceback (most recent call last):
  File "main.py", line 1, in <module>
    import package
  File "C:\Users\Patrick\Desktop\project\package\__init__.py", line 1, in <module>
    from .module import test
  File "C:\Users\Patrick\Desktop\project\package\module.py", line 3, in <module>
    with open("../data/test.csv") as f:
FileNotFoundError: [Errno 2] No such file or directory: '../data/test.csv'

However, if I run module.py from the package directory I get no errors.但是,如果我从package目录运行module.py ,则不会出现任何错误。 So it seems that the relative path used in open(...) is only relative to where the originating file is being run from (ie __name__ == "__main__" )?因此,似乎open(...)使用的相对路径仅与运行原始文件的位置有关(即__name__ == "__main__" )? I don't want to use absolute paths.我不想使用绝对路径。 What are some ways to deal with this?有什么方法可以解决这个问题?

Relative paths are relative to current working directory .相对路径是相对于当前工作目录的 If you do not your want your path to be, it must be absolute.如果您不希望自己的路径成为,那么它必须是绝对的。

But there is an often used trick to build an absolute path from current script: use its __file__ special attribute:但是有一个常用的技巧可以从当前脚本构建绝对路径:使用它的__file__特殊属性:

from pathlib import Path

path = Path(__file__).parent / "../data/test.csv"
with path.open() as f:
    test = list(csv.reader(f))

This requires python 3.4+ (for the pathlib module).这需要 python 3.4+(对于pathlib模块)。

If you still need to support older versions, you can get the same result with:如果你仍然需要支持旧版本,你可以得到相同的结果:

import csv
import os.path

my_path = os.path.abspath(os.path.dirname(__file__))
path = os.path.join(my_path, "../data/test.csv")
with open(path) as f:
    test = list(csv.reader(f))

[ 2020 edit: python3.4+ should now be the norm, so I moved the pathlib version inspired by jpyams' comment first] [ 2020 编辑: python3.4+ 现在应该是常态,所以我首先移动了受 jpyams 评论启发的 pathlib 版本]

For Python 3.4+:对于 Python 3.4+:

import csv
from pathlib import Path

base_path = Path(__file__).parent
file_path = (base_path / "../data/test.csv").resolve()

with open(file_path) as f:
    test = [line for line in csv.reader(f)]

这对我有用。

with open('data/test.csv') as f:

 

My Python version is Python 3.5.2 and the solution proposed in the accepted answer didn't work for me.我的 Python 版本是Python 3.5.2 ,接受的答案中提出的解决方案对我不起作用。 I've still were given an error我仍然收到错误

FileNotFoundError: [Errno 2] No such file or directory

when I was running my_script.py from the terminal.当我从终端运行my_script.py Although it worked fine when I run it through Run/Debug Configurations from PyCharm IDE (PyCharm 2018.3.2 (Community Edition)).尽管当我通过 PyCharm IDE(PyCharm 2018.3.2(社区版))的运行/调试配置运行它时它运行良好。

Solution :解决方案

instead of using:而不是使用:

my_path = os.path.abspath(os.path.dirname(__file__)) + some_rel_dir_path 

as suggested in the accepted answer, I used:正如接受的答案中所建议的那样,我使用了:

my_path = os.path.abspath(os.path.dirname(os.path.abspath(__file__))) + some_rel_dir_path

Explanation : Changing os.path.dirname(__file__) to os.path.dirname(os.path.abspath(__file__)) solves the following problem:说明:将os.path.dirname(__file__)改为os.path.dirname(os.path.abspath(__file__))解决了以下问题:

When we run our script like that: python3 my_script.py the __file__ variable has a just a string value of "my_script.py" without path leading to that particular script.当我们像这样运行我们的脚本时: python3 my_script.py __file__变量只有一个字符串值“my_script.py”,没有通向该特定脚本的路径。 That is why method dirname(__file__) returns an empty string "".这就是方法dirname(__file__)返回空字符串 "" 的原因。 That is also the reson why my_path = os.path.abspath(os.path.dirname(__file__)) + some_rel_dir_path is actually the same thing as my_path = some_rel_dir_path .这也是为什么my_path = os.path.abspath(os.path.dirname(__file__)) + some_rel_dir_path实际上与my_path = some_rel_dir_path相同的my_path = some_rel_dir_path Consequently FileNotFoundError: [Errno 2] No such file or directory is given when trying to use open method because there is no directory like "some_rel_dir_path".因此FileNotFoundError: [Errno 2] No such file or directory尝试使用open方法时FileNotFoundError: [Errno 2] No such file or directory因为没有像“some_rel_dir_path”这样的目录。

Running script from PyCharm IDE Running/Debug Configurations worked because it runs a command python3 /full/path/to/my_script.py (where "/full/path/to" is specified by us in "Working directory" variable in Run/Debug Configurations) instead of just python3 my_script.py like it is done when we run it from the terminal.从 PyCharm IDE 运行/调试配置运行脚本之所以有效,是因为它运行命令python3 /full/path/to/my_script.py (其中“/full/path/to”由我们在运行/调试的“工作目录”变量中指定配置),而不是像我们从终端运行它时那样只做python3 my_script.py

Hope that will be useful.希望这将是有用的。

尝试

with open(f"{os.path.dirname(sys.argv[0])}/data/test.csv", newline='') as f:

I was thundered when the following code worked.当以下代码起作用时,我感到震惊。

import os

for file in os.listdir("../FutureBookList"):
    if file.endswith(".adoc"):
        filename, file_extension = os.path.splitext(file)
        print(filename)
        print(file_extension)
        continue
    else:
        continue

So, I checked the documentation and it says:所以,我检查了文档,它说:

Changed in version 3.6: Accepts a path-like object.在 3.6 版更改: 接受一个类似路径的对象。

path-like object : 类路径对象

An object representing a file system path.表示文件系统路径的对象。 A path-like object is either a str or...类似路径的对象是 str 或...

I did a little more digging and the following also works:我做了更多的挖掘,以下也有效:

with open("../FutureBookList/file.txt") as file:
   data = file.read()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM