Zbuduj pełną ścieżkę do nazwy pliku w Pythonie

181

Muszę przekazać nazwę ścieżki pliku do modułu. Jak zbudować ścieżkę do pliku na podstawie nazwy katalogu, podstawowej nazwy pliku i ciągu formatu pliku?

Katalog może istnieć lub nie istnieć w momencie połączenia.

Na przykład:

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

Muszę stworzyć ciąg '/home/me/dev/my_reports/daily_report.pdf'

Ręczne łączenie elementów nie wydaje się dobrym sposobem. Próbowałem os.path.join:

join(dir_name,base_filename,format)

ale to daje

/home/me/dev/my_reports/daily_report/pdf
Damon Julian
źródło

Odpowiedzi:

290

To działa dobrze:

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

Należy pamiętać, że os.path.join()istnieje tylko dlatego, że różne systemy operacyjne używają różnych znaków separatora ścieżek. Wygładza tę różnicę, więc kod międzyplatformowy nie musi być zaśmiecany specjalnymi przypadkami dla każdego systemu operacyjnego. Nie ma potrzeby tego robić w przypadku „rozszerzeń” nazw plików (patrz przypis), ponieważ w każdym systemie operacyjnym są one zawsze połączone z resztą nazwy za pomocą kropki.

Jeśli użycie funkcji i tak sprawia, że ​​czujesz się lepiej (i lubisz niepotrzebnie komplikować swój kod), możesz to zrobić:

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

Jeśli wolisz, aby kod był czysty, po prostu umieść kropkę w sufiksie:

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

(To podejście jest również zgodne z konwencjami sufiksów w pathlib , które zostały wprowadzone w Pythonie 3.4).


Przypis: W systemach operacyjnych innych niż Micorsoft nie istnieje coś takiego jak „rozszerzenie” nazwy pliku. Jego obecność w systemie Windows pochodzi z MS-DOS i FAT, które zapożyczyły go od CP / M, który nie żyje od dziesięcioleci. Ta kropka plus trzy litery, do których wielu z nas jest przyzwyczajonych, to tylko część nazwy pliku w każdym innym nowoczesnym systemie operacyjnym, w którym nie ma wbudowanego znaczenia.

ʇsәɹoɈ
źródło
7
Wspomniałeś, że separator systemu operacyjnego może nie być .. Do tego można użyć os.extsep.
sjbx
2
Nie wspomniałem o czymś takim.
ʇsәɹoɈ
6
Doszedłeś do tego, aby wyjaśnić, że „Rozszerzenia nazw plików” mają istotne znaczenie tylko w jednym głównym systemie operacyjnym (są po prostu częścią nazwy pliku w systemach innych niż Windows), a ich separatorem jest zawsze kropka ”. PO wyraził również, że zobaczył / pdf na końcu. Więc mogłeś to zrobić os.path.join(dir_name, base_filename, os.extsep, extension). Twoja odpowiedź jest całkowicie poprawna.
sjbx
3
Tak, masz rację, zwraca tylko ciąg, więc os.path.join (dir_name, '' .join ([base_filename, os.extsep, extension])) powinien to zrobić. Ponownie, nie podważa to poprawności twojej odpowiedzi.
sjbx,
1
@sjbx należy umieścić +między częściami nazw plików. os.path.join()dodaje separatory ścieżek specyficzne dla systemu operacyjnego ( /na przykład) między argumentami (ponieważ @ sәɹoɈ poprawnie ma je w swojej odpowiedzi. Dlatego poprawna forma fragmentu kodu to:os.path.join(dir_name, base_filename + os.extsep + extension)
Shayan Amani
40

Jeśli masz szczęście, że korzystasz z Pythona 3.4+, możesz użyć pathlib:

>>> from pathlib import Path
>>> dirname = '/home/reports'
>>> filename = 'daily'
>>> suffix = '.pdf'
>>> Path(dirname, filename).with_suffix(suffix)
PosixPath('/home/reports/daily.pdf')
Eugene Yarmash
źródło
1
Uważam, że pathlib jest znacznie bardziej elegancki niż os.path.join, który wydaje się dość niezgrabny w porównaniu.
pionierem
Nie działa, jeśli nazwa pliku zawiera „.” >>> filename2 = 'daily.hourly' >>> Ścieżka (nazwa katalogu, nazwa_pliku2) .with_suffix (sufiks) Wynik: WindowsPath ('/ home / reports / daily.pdf')
wontleave
2
@wontleave: jeśli nazwa pliku ma już sufiks, with_suffix()zastąpi go zamiast dołączania. Chcesz czegoś takiegoPath(dirname, filename2 + suffix)
Eugene Yarmash
22

Um, czemu nie tylko:

>>>> import os
>>>> os.path.join(dir_name, base_filename + "." + format)
'/home/me/dev/my_reports/daily_report.pdf'
Mark Longair
źródło
dzięki, ale miałem nadzieję, że istnieje bardziej przejrzysty sposób dołączania tego rozszerzenia… python ma nawet funkcję splitext do odcięcia rozszerzenia… więc musi być coś na odwrót
Damon Julian,
2
Funkcja splitext zachowuje znak „.” z przodu przedłużenia. To prawdopodobnie najczystszy sposób na zrobienie tego. Jeśli chcesz, aby wyglądał on bardziej czytelnie w Twoim kodzie, sugerowałbym użycie funkcji lub funkcji lambda.
Wirowość
0

Po prostu użyj, os.path.joinaby połączyć swoją ścieżkę z nazwą pliku i rozszerzeniem. Użyj, sys.argvaby uzyskać dostęp do argumentów przekazanych do skryptu podczas jego wykonywania:

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

Po prostu uruchom skrypt, taki jak:

   # on windows-based systems
   python script.py year

   # on unix-based systems
   ./script.py year
Albert
źródło