Pythonでファイル・ディレクトリを削除するos.remove, shutil.rmtreeなど

Pythonでファイルを削除するにはos.remove()、ディレクトリ(フォルダ)を中のファイルやサブディレクトリごとすべて削除するにはshutil.rmtree()を使います。空のディレクトリのみを削除対象とするos.rmdir(), os.removedirs()もあります。 osモジュールもshutilモジュールも標準ライブラリに含まれているので追加のインストールは不要(importは必要)。 以下の内容について説明します。

ファイルを削除: os.remove() ディレクトリを中身ごと削除: shutil.rmtree() ディレクトリを空にする 空のディレクトリを削除: os.rmdir(), os.removedirs() 複数のファイルを一括で削除 ワイルドカードで条件指定 正規表現で条件指定いずれの場合もゴミ箱に入れられることなく削除されるので気をつけてください。削除ではなくshutil.move()で別のディレクトリに移動するという方法もあります。

また、Python3.4以降ではパスをオブジェクトとして操作できるpathlibモジュールを使ってファイルやディレクトリを削除することもできます。条件を満たすファイルの一覧を取得して削除するような処理はpathlibを使ったほうが書きやすい。

ファイルを削除: os.remove()

ファイルを削除するのはos.remove()。

os.remove() --- 雑多なオペレーティングシステムインタフェース — Python 3.7.0 ドキュメント

例として以下のようにディレクトリ、ファイルを作成。

import os

os.makedirs('temp/', exist_ok=True)

with open('temp/file.txt', 'w') as f:
    f.write('')

print(os.listdir('temp'))
# ['file.txt']

引数にファイルのパスを指定すると削除されます。

os.remove('temp/file.txt')

print(os.listdir('temp'))
# []

os.remove()で削除できるのはファイルのみ。ディレクトリ(フォルダ)のパスを指定するとエラーになります。

# os.remove('temp/')
# PermissionError: [Errno 1] Operation not permitted: 'temp/'

ディレクトリを削除したい場合は以下で説明するshutil.rmtree()やos.rmdir(), os.removedirs()などを使います。

ディレクトリを中身ごと削除: shutil.rmtree()

ディレクトリを中のファイルやサブディレクトリごと削除するにはshutil.rmtree()を使います。

shutil.rmtree() --- 高水準のファイル操作 — Python 3.7.0 ドキュメント

空のディレクトリのみを削除したい場合はos.rmdir(), os.removedirs()(後述)。 例として以下のようにディレクトリ、ファイルを作成。

import shutil
import os

os.makedirs('temp/dir/sub_dir/', exist_ok=True)

with open('temp/dir/file.txt', 'w') as f:
    f.write('')

print(os.listdir('temp/'))
# ['dir']

print(os.listdir('temp/dir/'))
# ['file.txt', 'sub_dir']

shutil.rmtree()の引数として指定できるのはディレクトリを示すパスのみ。ファイルだとエラー。

# shutil.rmtree('temp/dir/file.txt')
# NotADirectoryError: [Errno 20] Not a directory: 'temp/dir/file.txt'

ディレクトリのパスを指定すると中のファイルやサブディレクトリごとまとめて削除されます。

shutil.rmtree('temp/dir/')

print(os.listdir('temp/'))
# []

サブディレクトリ内にさらにファイルやディレクトリが存在する場合も再帰的にすべて削除されます。

ディレクトリを空にする

ディレクトリを空にする場合は shutil.rmtree()で全部削除してから新しく同名のディレクトリをos.mkdir()で作成するのが簡単。

import os
import shutil

os.makedirs('temp/dir/', exist_ok=True)

with open('file.txt', 'w') as f:
    f.write('')

print(os.listdir('temp/'))
# ['dir', 'test.txt']

target_dir = 'temp'

shutil.rmtree(target_dir)
os.mkdir(target_dir)

print(os.listdir('temp/'))
# []

ディレクトリ内の複数のファイルを条件に応じて一括で削除する方法は後述します。

空のディレクトリを削除: os.rmdir(), os.removedirs()

空のディレクトリのみを削除対象とするos.rmdir(), os.removedirs()もあります。

os.rmdir() --- 雑多なオペレーティングシステムインタフェース — Python 3.7.0 ドキュメント os.removedirs() --- 雑多なオペレーティングシステムインタフェース — Python 3.7.0 ドキュメント

os.rmdir()は空のディレクトリ一つが対象。

import os

os.makedirs('temp/dir_empty/', exist_ok=True)

print(os.listdir('temp/'))
# ['dir_empty']

os.rmdir('temp/dir_empty/')

print(os.listdir('temp/'))
# []

ディレクトリが空でない(ファイルやサブディレクトリを含んでいる)場合はエラーとなります。

os.makedirs('temp/dir_not_empty/', exist_ok=True)

with open('temp/dir_not_empty/file.txt', 'w') as f:
    f.write('')

# os.rmdir('temp/dir_not_empty/')
# OSError: [Errno 66] Directory not empty: 'temp/dir_not_empty/'

例外処理を行えばエラー(例外)で終了させずにディレクトリが空のときのみ削除することができます。以下の例ではディレクトリが空ではない場合はpassで何の処理も行わずにスルーさせています。

try:
    os.rmdir('temp/dir_not_empty/')
except OSError as e:
    pass

中身をまとめて削除する場合は上述のshutil.rmtree()を使います。

import shutil

shutil.rmtree('temp/dir_not_empty/')

print(os.listdir('temp/'))
# []

os.removedirs()は空のディレクトリを末端から再帰的に削除します。引数に末端の空ディレクトリを指定すると、親ディレクトリが空である場合に順番に削除されます。

例えば、 os.removedirs('foo/bar/baz') では最初にディレクトリ 'foo/bar/baz' を削除し、次に 'foo/bar' さらに 'foo' をそれらが空ならば削除します。末端のディレクトリが削除できなかった場合には OSError が送出されます。 os.removedirs() --- 雑多なオペレーティングシステムインタフェース — Python 3.7.0 ドキュメント

import os

os.makedirs('temp/dir1/dir2/dir3/', exist_ok=True)

with open('temp/file.txt', 'w') as f:
    f.write('')

print(os.listdir('temp/'))
# ['file.txt', 'dir1']

os.removedirs('temp/dir1/dir2/dir3/')

print(os.listdir('temp/'))
# ['file.txt']

複数のファイルを一括で削除

os.remove()を使った実践的な例として、条件に応じて複数のファイルを一括で削除する方法を説明します。

ワイルドカードで条件指定

globモジュールを使うとワイルドカード*などの特殊文字(メタ文字)を使ってファイルやディレクトリの一覧をリストで取得できます。

以下のようなファイル・ディレクトリ構成を例とします。 temp/ ├── 012.txt ├── abc.txt ├── dir │ ├── 789.txt │ └── xyz.text └── file.text

glob.glob()の第一引数にワイルドカードなどを含む文字列を指定します。

import glob

print(glob.glob('temp/*.txt'))
# ['temp/abc.txt', 'temp/012.txt']

Python3.5からは**と引数recursive=Trueを合わせて再帰的な処理ができます。

print(glob.glob('temp/**', recursive=True))
# ['temp/', 'temp/file.text', 'temp/abc.txt', 'temp/012.txt', 'temp/dir', 'temp/dir/xyz.text', 'temp/dir/789.txt']

サブディレクトリ内も含めて任意の拡張子のファイルのリストを取得するには以下のようにします。

print(glob.glob('temp/**/*.txt', recursive=True))
# ['temp/abc.txt', 'temp/012.txt', 'temp/dir/789.txt']

print(glob.glob('temp/**/*.text', recursive=True))
# ['temp/file.text', 'temp/dir/xyz.text']

?は任意の一文字、[]はカッコ内の一文字にマッチします。

print(glob.glob('temp/**/???.text', recursive=True))
# ['temp/dir/xyz.text']

print(glob.glob('temp/**/[0-9][0-9][0-9].txt', recursive=True))
# ['temp/012.txt', 'temp/dir/789.txt']

正規表現ではないので+で1回以上の繰り返しを指定したりはできません。正規表現を使った例は後述します。 以下のような関数を定義するとglob.glob()で抽出された複数のファイルを一括で削除できます。

import os
import glob

def remove_glob(pathname, recursive=True):
    for p in glob.glob(pathname, recursive=recursive):
        if os.path.isfile(p):
            os.remove(p)

ディレクトリのパスが抽出されることもあるのでos.path.isfile()でファイルのみを対象としています。

サブディレクトリ内も含めて、拡張子txtのファイルを削除します。

remove_glob('temp/**/*.txt')

削除後のファイルは以下の通り。 temp/ ├── dir │ └── xyz.text └── file.text

ディレクトリをマッチさせて削除したい場合はos.path.isfile()とos.remove()のかわりにos.path.isdir()とshutil.rmtree()を使えば問題ありません。

正規表現で条件指定

正規表現で条件を指定したい場合はreモジュールを使います。

上の例と同じく以下のようなファイル・ディレクトリ構成を例とします。 temp/ ├── 012.txt ├── abc.txt ├── dir │ ├── 789.txt │ └── xyz.text └── file.text

glob.glob()で**と引数recursive=Trueを使ってすべてのファイル、ディレクトリを再帰的にリストアップしてからre.search()などで正規表現を使った判定を行う。 リストを取得したい場合は以下のようにリスト内包表記が使えます。

import glob
import re

print(glob.glob('temp/**', recursive=True))
# ['temp/', 'temp/file.text', 'temp/abc.txt', 'temp/012.txt', 'temp/dir', 'temp/dir/xyz.text', 'temp/dir/789.txt']

print([p for p in glob.glob('temp/**', recursive=True) if re.search('\d+\.txt', p)])
# ['temp/012.txt', 'temp/dir/789.txt']

print([p for p in glob.glob('temp/**', recursive=True) if re.search('/\D{3}\.(txt|text)', p)])
# ['temp/abc.txt', 'temp/dir/xyz.text']

\dは数字、+は1回以上の繰り返し。\Dは数字以外の文字、{n}はn回の繰り返し。また、(a|b)はa, bのいずれかとなります。globだけでは実現できない複雑な条件が指定できます。 以下のような関数を定義すると、glob.glob()および正規表現で抽出された複数のファイルを一括で削除できます。

import os
import glob
import re

def remove_glob_re(pattern, pathname, recursive=True):
    for p in glob.glob(pathname, recursive=recursive):
        if os.path.isfile(p) and re.search(pattern, p):
            os.remove(p)

サブディレクトリ内も含めて、拡張子txtでファイル名が数字のみのファイルを削除します。

remove_glob_re('\d+.txt', 'temp/**')

削除後のファイルは以下の通り。 temp/ ├── abc.txt ├── dir │ └── xyz.text └── file.text

なお、ファイル・ディレクトリ数が多い場合にglob.glob()で**を使うと時間がかかる可能性があるので、他の特殊文字で条件を絞れる場合はそちらを使ったほうがいい。

Last Updated: 6/26/2019, 10:34:03 PM