[解決!Python]splitext関数でファイルパスから拡張子を取得するには解決!Python

os.path.splitext関数は渡されたパスを拡張子とそれ以外の部分に分割する。その基本的な使い方と注意点、拡張子ごとに処理を切り分けるサンプルコードを紹介する。

» 2024年03月12日 05時00分 公開
[かわさきしんじDeep Insider編集部]
「解決!Python」のインデックス

連載目次

from os.path import splitext

# os.path.splitext関数はパスを拡張子とそれ以外に分割する
w_file = 'C:\\tmp\\pytips\\foo.txt'
u_file = '/tmp/pytips/foo.txt'

result = splitext(w_file)
print(result)  # ('C:\\tmp\\pytips\\foo', '.txt')
result = splitext(u_file)
print(result)  # ('/tmp/pytips/foo', '.txt')

w_dir = 'C:\\tmp\\pytips\\'
u_dir = '/tmp/pytips/'

result = splitext(w_dir)
print(result)  # ('C:\\tmp\\pytips\\', '')
result = splitext(u_dir)
print(result)  # ('/tmp/pytips/', '')

# PathクラスのインスタンスでもOK
from pathlib import Path

u_file = Path(u_file)
print(u_file)  # /tmp/pytips/foo.txt
result = splitext(u_file)
print(result)  # ('/tmp/pytips/foo', '.txt')

# os.path.splitext関数は最後の拡張子以降を拡張子として扱う
f = '/tmp/foo/bar.tar.gz'
result = splitext(f)
print(result)  # ('/tmp/foo/bar.tar', '.gz')

f = '/tmp/foo/readme'
result = splitext(f)  # 拡張子がなければタプルの拡張子部分は空文字列
print(result)  # ('/tmp/foo/readme', '')

# 拡張子に応じて何らかの処理を行う
# 準備
from pathlib import Path

d = Path('pytips/test')
d.mkdir(parents=True, exist_ok=True)

f0 = Path(d, 'foo.txt'# 'pytips/test/foo.txt'
f1 = d / Path('bar.csv'# 'pytips/test/bar.csv'
f2 = d / 'baz.tsv'  # pytips/test/baz.tsv'

print(d)  # pytips/test
print(f0)  # pytips/test/foo.txt
print(f1)  # pytips/test/bar.csv
print(f2)  # pytips/test/baz.tsv

f0.touch()
f1.touch()
f2.touch()

# Path.iterdirメソッドでディレクトリを走査する
for item in d.iterdir():
    root, ext = splitext(item)
    match(ext):
        case '.txt':
            print('processing a text file:', item)
        case '.csv' | '.tsv':
            print('processing a csv/tsv file:', item)
        case _:
            print('do nothing:', item)

# os.scandir関数でディレクトリを走査する
import os
for item in os.scandir(d):
    root, ext = splitext(item)  # DirEntryクラスのインスタンスでもOK
    if ext == '.txt':
        print('processing a text file:', item.name)
    elif ext == '.csv' or ext == '.tsv':
        print('processing a csv/tsv file:', item.name)
    else:
        print('do nothing:', item.name)


os.path.splitext関数

 os.pathモジュールにはパスを特定の条件で分割する関数が幾つかある。

  • os.path.split関数:パスを「(パスの末尾より前, パスの末尾)」という2要素のタプルに分割する
  • os.path.splitdrive関数:パスを「(ドライブ, それ以外)」という2要素のタプルに分割する
  • os.path.splitext関数:パスを「(拡張子以外の部分, 拡張子)」という2要素のタプルに分割する
  • os.path.splitroot関数:パスを「(ドライブ, パスの末尾より前, パスの末尾)」という3要素のタプルに分割する(Python 3.12以降)

 このうち、以下ではos.path.splitext関数を使って、パスを拡張子とそれ以外の部分に分割する方法を紹介する。

 以下にos.path.splitext関数の構文を示す。

os.path.splitext(path)


 os.path.splitext関数はパラメーターを1つ持ち、これにパスを渡すと「(拡張子以外の部分, 拡張子)」という2つの要素からなるタプルが返される。

 基本的な例を以下に示す。

from os.path import splitext

# os.path.splitext関数はパスを拡張子とそれ以外に分割する
w_file = 'C:\\tmp\\pytips\\foo.txt'
u_file = '/tmp/pytips/foo.txt'

result = splitext(w_file)
print(result)  # ('C:\\tmp\\pytips\\foo', '.txt')
result = splitext(u_file)
print(result)  # ('/tmp/pytips/foo', '.txt')


 変数w_fileにはWindows形式のパス(テキストファイルを表している)が、変数u_fileにはUnix形式のパス(こちらもテキストファイルを表している)が代入されている。これらをos.path.splitext関数に渡すと結果は「('C:\\tmp\\pytips\\foo', '.txt')」「('/tmp/pytips/foo', '.txt')」と拡張子以外の部分と拡張子を含んだタプルが得られる。

 注意したいのは、拡張子の部分がピリオドで始まっている点だ。

 次のように拡張子を含まないパス(多くの場合はディレクトリやフォルダーを意味しているだろう)を渡すと、タプルの拡張子部分は空文字列となる。

w_dir = 'C:\\tmp\\pytips\\'
u_dir = '/tmp/pytips/'

result = splitext(w_dir)
print(result)  # ('C:\\tmp\\pytips\\', '')
result = splitext(u_dir)
print(result)  # ('/tmp/pytips/', '')


 ここまでパスとして文字列を渡していたが、os.path.splitext関数にはいわゆる「path-likeオブジェクト」を渡してもよい。そうしたオブジェクトとして典型的なのがpathlibモジュールのPathクラスのインスタンスだ。

from pathlib import Path

u_file = Path(u_file)
print(u_file)  # /tmp/pytips/foo.txt
result = splitext(u_file)
print(result)  # ('/tmp/pytips/foo', '.txt')


 この例では、文字列として表現されていたパスをPathクラスのインスタンスに変換子、それをos.path.splitext関数に渡している。

 パスの最後の構成要素が複数のピリオドを含んでいる場合、os.path.splitext関数は最後のピリオド以降を拡張子として扱う。以下に例を示す。

f = '/tmp/foo/bar.tar.gz'
result = splitext(f)
print(result)  # ('/tmp/foo/bar.tar', '.gz')


 ここではパスは/tmp/fooディレクトリにあるbar.tar.gzファイルを指しているが、これをos.path.splitext関数に渡すと最後のピリオド以降の「.gz」が拡張子として扱われる。

 逆に拡張子がない場合は(先ほども見たが)、戻り値となるタプルの拡張子部分は空文字列になる。以下の例ではreadmeファイルを指しているパスをos.path.splitext関数に渡しているが、戻り値であるタプルの拡張子部分は空文字列になっている。

f = '/tmp/foo/readme'
result = splitext(f)  # 拡張子がなければタプルの拡張子部分は空文字列
print(result)  # ('/tmp/foo/readme', '')


拡張子に応じて何らかの処理を行う

 最後に、os.path.splitext関数で拡張子を取り出して、その種類に応じた処理を行う例を示す。その準備として、ここではカレントディレクトリにpytipsディレクトリを作成し、その下にさらにtestディレクトリを作成して、そこに3つのファイルを配置している。

from pathlib import Path

d = Path('pytips/test')
d.mkdir(parents=True, exist_ok=True)

f0 = Path(d, 'foo.txt'# 'pytips/test/foo.txt'
f1 = d / Path('bar.csv'# 'pytips/test/bar.csv'
f2 = d / 'baz.tsv'  # pytips/test/baz.tsv'

print(d)  # pytips/test
print(f0)  # pytips/test/foo.txt
print(f1)  # pytips/test/bar.csv
print(f2)  # pytips/test/baz.tsv

f0.touch()
f1.touch()
f2.touch()


 最初にPath.iterdirメソッドでpytips/testディレクトリを走査して、そこにある3つのファイルの拡張子を得て、match文で処理を分岐させる例だ。

for item in d.iterdir():
    root, ext = splitext(item)
    match(ext):
        case '.txt':
            print('processing a text file:', item)
        case '.csv' | '.tsv':
            print('processing a csv/tsv file:', item)
        case _:
            print('do nothing:', item)


 2つ目のcaseブロックでは「case '.csv' | '.tsv':」として拡張子が'.csv'と'.tsv'の場合の処理をまとめている(実際には区切り文字が異なるため、このように処理をまとめるのは難しいかもしれない)。

 同じことをos.scandir関数とif文の組み合わせで行う例は以下の通りだ。

import os
for item in os.scandir(d):
    root, ext = splitext(item)  # DirEntryクラスのインスタンスでもOK
    if ext == '.txt':
        print('processing a text file:', item.name)
    elif ext == '.csv' or ext == '.tsv':
        print('processing a csv/tsv file:', item.name)
    else:
        print('do nothing:', item.name)


 os.scandir関数で列挙されるのはDirEntryクラスのインスタンスだが、これもpath-likeオブジェクトなので、os.path.splitext関数には問題なく渡せる点にも注意しよう。

「解決!Python」のインデックス

解決!Python

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。