我该如何从各个部分(例如文件夹路径、名称和扩展名)创建一个完整的文件路径?

278

我需要将文件路径名传递给一个模块。如何从目录名称、基本文件名和文件格式字符串构建文件路径?

在调用时,该目录可能存在也可能不存在。

例如:

dir_name='/home/me/dev/my_reports'
base_filename='daily_report'
format = 'pdf'

我需要创建一个字符串'/home/me/dev/my_reports/daily_report.pdf'
手动连接这些部分似乎不是一个好方法。我尝试了os.path.join:
join(dir_name,base_filename,format)

但它会给出

/home/me/dev/my_reports/daily_report/pdf

1
拼接有什么问题吗? - undefined
拼接有什么问题? - user313032
7个回答

429

这个很好用:

os.path.join(dir_name, base_filename + '.' + filename_suffix)

请记住,os.path.join() 之所以存在,是因为不同的操作系统使用不同的路径分隔符字符。它可以平滑地处理这种差异,使跨平台代码不必为每个操作系统编写特殊情况。对于文件名 "扩展名"(见脚注),没有必要这样做,因为它们始终在每个实现它们的操作系统上都由点字符前缀。
如果使用函数让您感觉更好(并且您喜欢不必要地使代码复杂化),可以这样做:
os.path.join(dir_name, '.'.join((base_filename, filename_suffix)))

如果您喜欢保持代码的整洁,只需在后缀中包含点号:

suffix = '.pdf'
os.path.join(dir_name, base_filename + suffix)

这种方法也恰好与pathlib中的后缀约定兼容,该库在Python 3.4中引入,比这个问题提出的时间晚了几年。不需要向后兼容的新代码可以这样做:

suffix = '.pdf'
pathlib.PurePath(dir_name, base_filename + suffix)

你可能会想要使用更短的Path()而不是PurePath(),如果你只处理本地操作系统的路径。鉴于原始问题背后的跨平台问题,我会质疑这个选择。
警告:不要使用pathlib的with_suffix()来实现此目的。如果base_filename包含一个点,该方法将损坏它。
脚注:在微软操作系统之外,不存在所谓的文件名“扩展名”。它在Windows上的存在来自于MS-DOS和FAT,这两者都从已经死亡几十年的CP/M中借鉴了它。许多人习惯于看到的那个点加三个字母只是其他现代操作系统上文件名的一部分,它没有内置的含义。

9
你提到操作系统分隔符可能不是 .,针对这种情况可以使用 os.extsep - sjbx
3
我没有提及过这件事。 - ʇsәɹoɈ
8
您在详细解释“文件名的扩展名只在一个主要操作系统上有显著意义(它们只是非Windows系统上文件名的一部分),并且它们的分隔符字符始终为点号”时候已经尽力了。提问者也表达了他们在结尾看到了“/pdf”。因此,您可以使用os.path.join(dir_name, base_filename, os.extsep, extension)来处理。您的回答完全正确。 - sjbx
3
没错,它只返回一个字符串,所以os.path.join(dir_name, ''.join([base_filename, os.extsep, extension]))就可以了。再次强调,这并不会影响你回答的正确性。 - sjbx
3
你应该在文件名的部分之间加上+号。os.path.join()会在参数之间添加特定于操作系统的路径分隔符(例如/),正如@sәɹoɈ在他/她的回答中正确地表述的那样。因此,你代码片段的正确形式是:os.path.join(dir_name, base_filename + os.extsep + extension) - Shayan Amani
显示剩余2条评论

73
在Python 3.4及以上版本中,可以像这样使用pathlib标准库模块:
>>> from pathlib import Path
>>> dirname, filename, suffix = '/home/reports', 'daily', '.pdf'
>>> Path(dirname, filename).with_suffix(suffix)
PosixPath('/home/reports/daily.pdf')

3
与 os.path.join 相比,我发现 pathlib 更加优雅,而 os.path.join 则显得相当笨重。 - pioniere
1
如果您的文件名中有“.”,则无法正常工作。
filename2= 'daily.hourly' Path(dirname, filename2).with_suffix(suffix) 输出:WindowsPath('/home/reports/daily.pdf')
- wontleave
5
如果文件名已经有后缀,with_suffix()将替换它而不是附加。你需要像这样的东西:Path(dirname, filename2 + suffix) - Eugene Yarmash
1
pathlib 还提供了一个巧妙的运算符重载:(Path(dirname) / filename).with_suffix(suffix) - Karl Knechtel

34
>>> import os
>>> os.path.join(dir_name, base_filename + "." + format)
'/home/me/dev/my_reports/daily_report.pdf'

谢谢,但我希望有一种更简洁的方法来追加那个扩展名。Python甚至有一个splitext函数可以去掉扩展名,所以肯定有一些方法可以做到相反的操作。 - Damon Julian
2
splitext函数会保留扩展名前面的'.',这可能是最简洁的方法。如果你想在代码中让它看起来更干净,我建议使用一个函数或lambda函数。 - Vorticity

1
为什么不直接将扩展名包含在基本文件名中呢?
dir_name='/home/me/dev/my_reports/'
base_filename='daily_report.pdf'
os.path.join(dir_name, base_filename)

0

只需使用os.path.join将路径与文件名和扩展名连接起来。使用sys.argv访问在执行脚本时传递给它的参数:

#!/usr/bin/env python3
# coding: utf-8

# import netCDF4 as nc
import numpy as np
import numpy.ma as ma
import csv as csv

import os.path
import sys

basedir = '/data/reu_data/soil_moisture/'
suffix = 'nc'


def read_fid(filename):
    fid = nc.MFDataset(filename,'r')
    fid.close()
    return fid

def read_var(file, varname):
    fid = nc.Dataset(file, 'r')
    out = fid.variables[varname][:]
    fid.close()
    return out


if __name__ == '__main__':
    if len(sys.argv) < 2:
        print('Please specify a year')

    else:
        filename = os.path.join(basedir, '.'.join((sys.argv[1], suffix)))
        time = read_var(ncf, 'time')
        lat = read_var(ncf, 'lat')
        lon = read_var(ncf, 'lon')
        soil = read_var(ncf, 'soilw')

只需像这样运行脚本:

   # on windows-based systems
   python script.py year

   # on unix-based systems
   ./script.py year

-1
import os
def createfile(name, location, extension):
    print(name, extension, location)
    #starting creating a file with some dummy contents
    path = os.path.join(location, name + '.' + extension)
    f = open(path, "a")
    f.write("Your contents!! or whatever you want to put inside this file.")
    f.close()
    print("File creation is successful!!")

def readfile(name, location, extension):
    #open and read the file after the appending:
    path = os.path.join(location, name + '.' + extension)
    f = open(path, "r")
    print(f.read())

#pass the parameters here
createfile('test','./','txt')
readfile('test','./','txt')

-1
from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.

BASE_DIR = Path(__file__).resolve().parent.parent
TEMPLATE_PATH = Path.joinpath(BASE_DIR,"templates")
print(TEMPLATE_PATH)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接