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

时间:2016-11-04 05:48:08

标签: python python-3.x io relative-path python-import

假设我有一个python项目,其结构如下:

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

__init__.py

from .module import test

module.py

import csv

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

main.py

import package

print(package.test)

当我运行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'

但是,如果我从module.py目录运行package,我没有错误。所以open(...)中使用的相对路径似乎只与起始文件的运行位置相关(即__name__ == "__main__")?我不想使用绝对路径。有什么方法可以解决这个问题?

6 个答案:

答案 0 :(得分:47)

相对路径相对于current working directory。 如果你不想要自己的道路,那一定是绝对的。

但是有一个常用的技巧来构建当前脚本的绝对路径:使用其__file__特殊属性:

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

注意,从python 3.4开始,__file__对于导入的模块始终是绝对的,您可以在此示例中删除os.path.abspath部分。并不是说它是绝对必要的,但是如果你在某个时候改变当前的工作目录而你的模块是用相对路径导入的,那就避免了意外。

答案 1 :(得分:6)

对于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)]

答案 2 :(得分:2)

我的Python版本是 Python 3.5.2 ,接受的答案中提出的解决方案对我不起作用。我仍然遇到错误

FileNotFoundError: [Errno 2] No such file or directory

当我从终端运行my_script.py时。尽管当我通过PyCharm IDE(PyCharm 2018.3.2(Community Edition))的“运行/调试配置”运行它时效果很好,

解决方案

代替使用:

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

根据接受的答案中的建议,我使用了:

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

说明: 将os.path.dirname(__file__)更改为os.path.dirname(os.path.abspath(__file__)) 解决了以下问题:

当我们像这样运行脚本时:python3 my_script.py __file__变量只有一个字符串值“ my_script.py”,而没有指向该特定脚本的路径。这就是为什么方法dirname(__file__)返回空字符串“”的原因。这也是为什么my_path = os.path.abspath(os.path.dirname(__file__)) + some_rel_dir_path实际上与my_path = some_rel_dir_path相同的原因。因此,在尝试使用FileNotFoundError: [Errno 2] No such file or directory方法时会给出open,因为没有像“ some_rel_dir_path”这样的目录。

PyCharm IDE运行/调试配置中的运行脚本起作用了,因为它运行命令python3 /full/path/to/my_script.py(其中“ / full / path / to”由我们在“运行/调试配置”中的“工作目录”变量中指定)就像python3 my_script.py一样,就像我们从终端运行它一样。

希望会有用。

答案 3 :(得分:1)

这对我有用。

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

 

答案 4 :(得分:0)

尝试

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

答案 5 :(得分:0)

当下面的代码起作用时,我很高兴。

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

因此,我检查了documentation,它说:

在3.6版中进行了更改:接受类似路径的对象。

path-like object

代表文件系统路径的对象。类路径对象是 一个str或...

我做了一个little more digging,以下操作也有效:

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