Build the full path filename in Python
PythonFilenamesPython Problem Overview
I need to pass a file path name to a module. How do I build the file path from a directory name, base filename, and a file format string?
The directory may or may not exist at the time of call.
For example:
dir_name='/home/me/dev/my_reports'
base_filename='daily_report'
format = 'pdf'
I need to create a string '/home/me/dev/my_reports/daily_report.pdf'
Concatenating the pieces manually doesn't seem to be a good way. I tried os.path.join
:
join(dir_name,base_filename,format)
but it gives
/home/me/dev/my_reports/daily_report/pdf
Python Solutions
Solution 1 - Python
This works fine:
os.path.join(dir_name, base_filename + "." + filename_suffix)
Keep in mind that os.path.join()
exists only because different operating systems use different path separator characters. It smooths over that difference so cross-platform code doesn't have to be cluttered with special cases for each OS. There is no need to do this for file name "extensions" (see footnote) because they are always connected to the rest of the name with a dot character, on every OS.
If using a function anyway makes you feel better (and you like needlessly complicating your code), you can do this:
os.path.join(dir_name, '.'.join((base_filename, filename_suffix)))
If you prefer to keep your code clean, simply include the dot in the suffix:
suffix = '.pdf'
os.path.join(dir_name, base_filename + suffix)
That approach also happens to be compatible with the suffix conventions in pathlib, which was introduced in python 3.4 a few years after this question was asked. New code that doesn't require backward compatibility can do this:
suffix = '.pdf'
pathlib.PurePath(dir_name, base_filename + suffix)
You might be tempted to use the shorter Path()
instead of PurePath()
if you're only handling paths for the local OS. I would question that choice, given the cross-platform issues behind the original question.
Warning: Do not use pathlib's with_suffix()
for this purpose. That method will corrupt base_filename
if it ever contains a dot.
Footnote: Outside of Micorsoft operating systems, there is no such thing as a file name "extension". Its presence on Windows comes from MS-DOS and FAT, which borrowed it from CP/M, which has been dead for decades. That dot-plus-three-letters that many of us are accustomed to seeing is just part of the file name on every other modern OS, where it has no built-in meaning.
Solution 2 - Python
If you are fortunate enough to be running Python 3.4+, you can use pathlib
:
>>> from pathlib import Path
>>> dirname = '/home/reports'
>>> filename = 'daily'
>>> suffix = '.pdf'
>>> Path(dirname, filename).with_suffix(suffix)
PosixPath('/home/reports/daily.pdf')
Solution 3 - Python
Um, why not just:
>>> import os
>>> os.path.join(dir_name, base_filename + "." + format)
'/home/me/dev/my_reports/daily_report.pdf'
Solution 4 - Python
Is not it better to add the format in the base filename?
dir_name='/home/me/dev/my_reports/'
base_filename='daily_report.pdf'
os.path.join(dir_name, base_filename)
Solution 5 - Python
Just use os.path.join
to join your path with the filename and extension. Use sys.argv
to access arguments passed to the script when executing it:
#!/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')
Simply run the script like:
# on windows-based systems
python script.py year
# on unix-based systems
./script.py year
Solution 6 - Python
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)