Construisez le nom de fichier du chemin complet en Python

188

Je dois transmettre un nom de chemin de fichier à un module. Comment créer le chemin du fichier à partir d'un nom de répertoire, d'un nom de fichier de base et d'une chaîne de format de fichier?

Le répertoire peut exister ou non au moment de l'appel.

Par exemple:

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

J'ai besoin de créer une chaîne '/home/me/dev/my_reports/daily_report.pdf'

Concaténer les pièces manuellement ne semble pas être un bon moyen. J'ai essayé os.path.join:

join(dir_name,base_filename,format)

mais ça donne

/home/me/dev/my_reports/daily_report/pdf
Damon Julian
la source

Réponses:

308

Cela fonctionne bien:

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

Gardez à l'esprit que cela os.path.join()n'existe que parce que différents systèmes d'exploitation utilisent des caractères de séparation de chemin différents. Cela atténue cette différence afin que le code multiplateforme ne soit pas encombré de cas particuliers pour chaque système d'exploitation. Il n'est pas nécessaire de faire cela pour les "extensions" de nom de fichier (voir note de bas de page) car elles sont toujours connectées au reste du nom avec un caractère point, sur chaque OS.

Si l'utilisation d'une fonction vous permet de vous sentir mieux (et que vous aimez compliquer inutilement votre code), vous pouvez le faire:

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

Si vous préférez garder votre code propre, incluez simplement le point dans le suffixe:

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

Cette approche est également compatible avec les conventions de suffixe dans pathlib , qui a été introduite dans python 3.4 après que cette question a été posée. Un nouveau code qui ne nécessite pas de compatibilité descendante peut le faire:

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

Vous préférerez peut-être le plus court Pathplutôt que PurePathsi vous ne gérez que des chemins pour le système d'exploitation local.

Attention: n'utilisez pas de pathlib with_suffix()à cette fin. Cette méthode sera corrompue base_filenamesi elle contient un point.


Note de bas de page: En dehors des systèmes d'exploitation Micorsoft, il n'existe pas de nom de fichier "extension". Sa présence sur Windows vient de MS-DOS et FAT, qui l'ont emprunté à CP / M, mort depuis des décennies. Ce point plus trois lettres que beaucoup d'entre nous ont l'habitude de voir n'est qu'une partie du nom de fichier sur tous les autres systèmes d'exploitation modernes, où il n'a pas de signification intégrée.

ʇsәɹoɈ
la source
7
Vous avez mentionné que le séparateur du système d'exploitation pourrait ne pas l'être .. Pour cela, on peut utiliser os.extsep.
sjbx
2
Je n'ai mentionné rien de tel.
ʇsәɹoɈ
6
Vous avez longuement expliqué que «les extensions de nom de fichier n'ont une signification significative que sur un système d'exploitation majeur (elles font simplement partie du nom de fichier sur les systèmes non Windows), et leur caractère séparateur est toujours un point». Le PO a également déclaré avoir vu / pdf à la fin. Donc vous auriez pu le faire os.path.join(dir_name, base_filename, os.extsep, extension). Votre réponse est parfaitement correcte.
sjbx
3
Ouais, vous avez raison, il ne renvoie qu'une chaîne donc os.path.join (dir_name, '' .join ([base_filename, os.extsep, extension])) devrait le faire. Encore une fois, cela ne nuit pas à l'exactitude de votre réponse.
sjbx
1
@sjbx vous devez placer +entre les parties du nom de fichier. os.path.join()ajoute des séparateurs de chemin spécifiques au système d'exploitation ( /par exemple) entre les arguments (car @ sәɹoɈ les a correctement dans sa réponse. Ainsi, la forme correcte de votre extrait de code est:os.path.join(dir_name, base_filename + os.extsep + extension)
Shayan Amani
42

Si vous avez la chance d'exécuter Python 3.4+, vous pouvez utiliser pathlib:

>>> from pathlib import Path
>>> dirname = '/home/reports'
>>> filename = 'daily'
>>> suffix = '.pdf'
>>> Path(dirname, filename).with_suffix(suffix)
PosixPath('/home/reports/daily.pdf')
Eugène Yarmash
la source
2
Je trouve pathlib beaucoup plus élégant que os.path.join, ce qui semble assez maladroit en comparaison.
pioniere
1
Ne fonctionne pas si votre nom de fichier a un "." >>> filename2 = 'daily.hourly' >>> Path (dirname, filename2) .with_suffix (suffix) Output: WindowsPath ('/ home / reports / daily.pdf')
quittera pas le
2
@wontleave: Si un nom de fichier a déjà un suffixe, with_suffix()le remplacera au lieu de l'ajouter. Vous voulez quelque chose commePath(dirname, filename2 + suffix)
Eugene Yarmash
23

Euh, pourquoi pas simplement:

>>>> import os
>>>> os.path.join(dir_name, base_filename + "." + format)
'/home/me/dev/my_reports/daily_report.pdf'
Mark Longair
la source
merci, mais j'espérais qu'il y avait un moyen plus propre d'ajouter cette extension..python a même une fonction splitext pour couper l'extension ... donc il doit y avoir quelque chose pour faire l'inverse
Damon Julian
2
La fonction splitext conserve le '.' à l'avant de l'extension. C'est probablement la façon la plus propre de le faire. Si vous voulez qu'il "regarde" plus propre dans votre code, je vous suggère d'utiliser une fonction ou une fonction lambda.
Vorticity
0

Utilisez simplement os.path.joinpour joindre votre chemin avec le nom de fichier et l'extension. Utilisez sys.argvpour accéder aux arguments passés au script lors de son exécution:

#!/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')

Exécutez simplement le script comme:

   # on windows-based systems
   python script.py year

   # on unix-based systems
   ./script.py year
Albert
la source