Pythonでパス文字列からファイル名・フォルダ名・拡張子を取得、結合

Modified: | Tags: Python, ファイル処理, 文字列

Pythonでパス文字列からファイル名・フォルダ名・拡張子を取得したり、文字列を結合してパスを生成したりするには、標準ライブラリのos.pathモジュールを使う。

以下のパス文字列を例とする。

import os

filepath = './dir/subdir/filename.ext'

実行環境はMac。Windowsの場合の例は最後に示す。

なお、ここで説明するのはパス文字列からファイル名・フォルダ名(ディレクトリ名)を取得(抽出)する方法。フォルダ内に存在するファイル名一覧・パス一覧などを取得したい場合は以下の記事を参照。

また、パスをオブジェクトとして操作するpathlibモジュールを使って同様にファイル名やフォルダ名、拡張子などを抽出することもできる。慣れるとpathlibのほうが使いやすい。

OSによるパスの区切り文字の違い

パスの区切り文字はOSによって異なる。

UNIX(Macを含む)ではスラッシュ/、Windowsではバックスラッシュ\が使われる。

Pythonが動作しているOSにおける区切り文字はos.sepまたはos.path.sepで取得、確認できる。どちらでも同じ。

print(os.sep)
# /

print(os.sep is os.path.sep)
# True

ファイル名を取得: os.path.basename()

パス文字列からファイル名を取得するにはos.path.basename()を使う。

拡張子ありのファイル名

os.path.basename()は拡張子を含むファイル名部分の文字列を返す。

filepath = './dir/subdir/filename.ext'

basename = os.path.basename(filepath)
print(basename)
# filename.ext

print(type(basename))
# <class 'str'>

拡張子なしのファイル名

拡張子を含まないファイル名を取得するには後述のos.path.splitext()と組み合わせる。

filepath = './dir/subdir/filename.ext'

basename_without_ext = os.path.splitext(os.path.basename(filepath))[0]
print(basename_without_ext)
# filename

なお、os.path.splitext()は最後(一番右側)のドット.で分割する。最初の(一番左側)のドット.で分割したい場合は文字列strsplit()メソッドを使う。

filepath_tar_gz = './dir/subdir/filename.tar.gz'

print(os.path.splitext(os.path.basename(filepath_tar_gz))[0])
# filename.tar

print(os.path.basename(filepath_tar_gz).split('.', 1)[0])
# filename

フォルダ名(ディレクトリ名)を取得: os.path.dirname()

パス文字列からフォルダ名(ディレクトリ名)を取得するにはos.path.dirname()を使う。フォルダ名部分の文字列が返される。

filepath = './dir/subdir/filename.ext'

dirname = os.path.dirname(filepath)
print(dirname)
# ./dir/subdir

print(type(dirname))
# <class 'str'>

ファイルの直上のフォルダ名のみを取得したい場合はos.path.basename()と組み合わせる。

subdirname = os.path.basename(os.path.dirname(filepath))
print(subdirname)
# subdir

ファイル名とフォルダ名のペアを取得: os.path.split()

ファイル名とフォルダ名(ディレクトリ名)を両方取得するにはos.path.split()を使う。

os.path.basename()で取得できるファイル名の文字列とos.path.dirname()で取得できるフォルダ名の文字列のタプルが返される。

filepath = './dir/subdir/filename.ext'

base_dir_pair = os.path.split(filepath)
print(base_dir_pair)
# ('./dir/subdir', 'filename.ext')

print(type(base_dir_pair))
# <class 'tuple'>

print(os.path.split(filepath)[0] == os.path.dirname(filepath))
# True

print(os.path.split(filepath)[1] == os.path.basename(filepath))
# True

タプルのアンパックを利用してそれぞれの変数に代入できる。

dirname, basename = os.path.split(filepath)
print(dirname)
# ./dir/subdir

print(basename)
# filename.ext

再度連結するには後述のos.path.join()を使う。

パス文字列がフォルダ(ディレクトリ)を示す場合の注意点

パス文字列がフォルダを示す場合、末尾に区切り文字があるかないかで結果が異なるので注意。

末尾に区切り文字がない場合。

dirpath_without_sep = './dir/subdir'
print(os.path.split(dirpath_without_sep))
# ('./dir', 'subdir')

print(os.path.basename(dirpath_without_sep))
# subdir

末尾に区切り文字がある場合。最下層のフォルダ名を取得するには、os.path.dirname()os.path.basename()を組み合わせる。

dirpath_with_sep = './dir/subdir/'
print(os.path.split(dirpath_with_sep))
# ('./dir/subdir', '')

print(os.path.basename(os.path.dirname(dirpath_with_sep)))
# subdir

拡張子を取得: os.path.splitext()

拡張子を取得するにはos.path.splitext()を使う。

拡張子とそれ以外に分割されてタプルとして返される。拡張子はドット.込みの文字列。

filepath = './dir/subdir/filename.ext'

root_ext_pair = os.path.splitext(filepath)
print(root_ext_pair)
# ('./dir/subdir/filename', '.ext')

print(type(root_ext_pair))
# <class 'tuple'>

+演算子で結合すると元のパス文字列に戻る。

root, ext = os.path.splitext(filepath)
print(root)
# ./dir/subdir/filename

print(ext)
# .ext

path = root + ext
print(path)
# ./dir/subdir/filename.ext

拡張子を変更したパス文字列を作成

元のパス文字列から拡張子だけを変更したパス文字列を作成するには、os.path.splitext()で取得できるタプルの最初(0始まりの0番目)の要素と任意の拡張子の文字列を結合する。

filepath = './dir/subdir/filename.ext'

other_ext_filepath = os.path.splitext(filepath)[0] + '.jpg'
print(other_ext_filepath)
# ./dir/subdir/filename.jpg

ドット(ピリオド)なしの拡張子を取得

ドット.なしの拡張子を取得したい場合はスライス[1:]で2文字目以降を指定する。

filepath = './dir/subdir/filename.ext'

ext_without_dot = os.path.splitext(filepath)[1][1:]
print(ext_without_dot)
# ext

.tar.gzのような場合

上述のファイル名取得の例で示したように、os.path.splitext()は最後(一番右側)のドット.で分割する。.tar.gzのような拡張子の場合は要注意。

filepath_tar_gz = './dir/subdir/filename.tar.gz'

print(os.path.splitext(filepath_tar_gz))
# ('./dir/subdir/filename.tar', '.gz')

ファイル名における最初(一番左側)のドット.で分割したい場合、文字列のsplit()メソッドを使うが、フォルダ部分にもドット.が含まれているとうまくいかない。

print(filepath_tar_gz.split('.', 1))
# ['', '/dir/subdir/filename.tar.gz']

os.path.split()で分割したあと、文字列のsplit()メソッドを適用し、後述のos.path.join()で連結すればよい。

文字列のsplit()メソッドでは区切り文字が含まれないので、os.path.splitext()と同様に拡張子にドット.をつけたい場合は注意。

dirname, basename = os.path.split(filepath_tar_gz)
basename_without_ext, ext = basename.split('.', 1)
path_without_ext = os.path.join(dirname, basename_without_ext)
print(path_without_ext)
# ./dir/subdir/filename

print(ext)
# tar.gz

ext_with_dot = '.' + ext
print(ext_with_dot)
# .tar.gz

ファイル名とフォルダ名を結合してパス文字列を作成: os.path.join()

ファイル名とフォルダ名を結合して新たなパス文字列を作成するにはos.path.join()を使う。

引数に指定した文字列がパス区切り文字で区切られて結合される。複数の文字列を指定できる。

path = os.path.join('dir', 'subdir', 'filename.ext')
print(path)
# dir/subdir/filename.ext

同じフォルダの別のファイルのパス文字列を作成

あるファイルと同一フォルダの別のファイルのパス文字列を作成したい場合は、os.path.dirname()os.path.join()を組み合わせる。

filepath = './dir/subdir/filename.ext'

other_filepath = os.path.join(os.path.dirname(filepath), 'other_file.ext')
print(other_filepath)
# ./dir/subdir/other_file.ext

異なるOSのフォーマットを利用

現在Pythonが動作しているOSではないOSのフォーマットでパス文字列を操作する場合は、osモジュールではなくそれぞれ別のモジュールをインポートして使う。

  • UNIX (現行のMac含む): posixpath
  • Windows: ntpath
  • Macintosh 9以前のMac: macpath

いずれのモジュールもos.pathと同一のインターフェイスを持っているため、これまでのサンプルコードのos.pathの部分をそれぞれのモジュール名(ntpathなど)に変更すれば動作する。

Windowsの場合の例

Windowsの場合の例を示す。

ここでは上述のntpathモジュールを使ってMac上で実行している。

Windowsで実行する場合は以下のサンプルコード中のntpathos.pathに置き換えても同様の結果となる。

区切り文字バックスラッシュとraw文字列

Windowsのパスの区切り文字はバックスラッシュ\

コード中の文字列でバックスラッシュを記述するにはエスケープする必要があるため、バックスラッシュを2文字連続して書く。print()ではバックスラッシュ1文字が出力される。

import ntpath

print(ntpath.sep)
# \

print('\\')
# \

print(ntpath.sep is '\\')
# True
source: os_ntpath.py

raw文字列(r'xxx')を使うとエスケープが無効になるのでWindowsで深い階層のパスを記述するのが楽。raw文字列と通常の文字列は書き方が違うだけで値としては等価。どちらを使ってもよい。

file_path = 'c:\\dir\\subdir\\filename.ext'
file_path_raw = r'c:\dir\subdir\filename.ext'

print(file_path == file_path_raw)
# True
source: os_ntpath.py

raw文字列については以下の記事を参照。バックスラッシュ1文字をraw文字列で表すことはできないので注意。

ファイル名、フォルダ名、拡張子の取得例

Windowsでも変わらず動作する。

print(ntpath.basename(file_path))
# filename.ext

print(ntpath.dirname(file_path))
# c:\dir\subdir

print(ntpath.split(file_path))
# ('c:\\dir\\subdir', 'filename.ext')
source: os_ntpath.py

ドライブ文字を取得・結合: os.path.splitdrive()

ドライブ文字を取得するにはos.path.splitdrive()を使う。サンプルコードではntpath.splitdrive()になっている。

コロン:込みのドライブ文字とそれ以外に分割しタプルを返す。

print(ntpath.splitdrive(file_path))
# ('c:', '\\dir\\subdir\\filename.ext')
source: os_ntpath.py

ドライブ文字のみ取得したい場合は1文字目を選択する。

drive_letter = ntpath.splitdrive(file_path)[0][0]

print(drive_letter)
# c
source: os_ntpath.py

ドライブ文字を結合するには注意が必要。

os.path.join()にそのまま渡すと上手くいかない。

print(ntpath.join('c:', 'dir', 'subdir', 'filename.ext'))
# c:dir\subdir\filename.ext
source: os_ntpath.py

区切り文字os.sep(サンプルコードではntpath.sep)も合わせてos.path.join()の引数として指定するか、ドライブ文字に区切り文字を加えてしまえばOK。

print(ntpath.join('c:', ntpath.sep, 'dir', 'subdir', 'filename.ext'))
# c:\dir\subdir\filename.ext

print(ntpath.join('c:\\', 'dir', 'subdir', 'filename.ext'))
# c:\dir\subdir\filename.ext
source: os_ntpath.py

関連カテゴリー

関連記事