Pythonの基礎 - ディレクトリ
概要
Pythonでは、ディレクトリに含まれるファイルの一覧を取得したり、ディレクトリ名を変更したりすることができる。
ディレクトリの作成 / 削除
ディレクトリの作成
ディレクトリを新規作成する場合は、mkdir関数を使用する。
mkdir関数は、第1引数に指定したパスが示すディレクトリを新規作成する。
省略可能な第2引数には、新規作成するディレクトリの権限を設定する。(省略された場合、8進数で0o777が設定される)
 os.mkdir(path, mode = 0o777, *, dir_fd = None)
 import os
 
 path = './test/movie'
 os.mkdir(path)
※注意
mkdir関数は、中間ディレクトリを作成することができない。
例えば、/home/hoge/img/backディレクトリを作成する場合、/home/hoge/imgディレクトリが存在していない時は、例外FileNotFoundErrorが発生する。
また、新規作成するディレクトリが既に存在する場合は、例外FileExistsErrorが発生する。
中間ディレクトリも同時に作成する
中間ディレクトリも同時に新規作成する場合、osモジュールのmakedirs関数を使用する。
第1引数に指定したパスが示すディレクトリを新規作成する。
省略可能な第2引数には、新規作成するディレクトリの権限を設定する。(省略した場合は、8進数で0o777が設定される)
省略可能な第3引数にTrueを指定する場合、新規作成するディレクトリが既に存在してもエラーが発生しない。
新規作成するディレクトリが既に存在する場合、引数を省略するか、明示的にexist_ok = Falseを指定すると例外FileExistsErrorが発生する。
 os.makedirs(name, mode = 0o777, exist_ok = False)
以下の例では、./test/movie/backディレクトリを新規作成している。
./test/movie/backディレクトリが存在しない場合でも、中間ディレクトリである./test/movieディレクトリを作成後、指定のパスのディレクトリが作成される。
 import os
 
 path = './test/movie/back'
 os.makedirs(path, exist_ok = True)
ディレクトリの削除
ファイルを削除する場合は、osモジュールのrmdir関数を使用する。
rmdir関数は、第1引数に指定したパスが示すファイルを削除する。
ただし、ディレクトリを削除する場合は、ディレクトリの中身が空である必要があることに注意する。
削除するディレクトリが空ではない場合、例外OSErrorが発生する。
 os.rmdir(path *, dir_fd = None)
存在しないファイルを削除する場合、例外FileNotFoundErrorが発生する。
 import os
 
 path = './test/doc'
 os.rmdir(path)
ディレクトリとディレクトリの中身の一括削除
ディレクトリとディレクトリ内に存在するファイルを一括して削除する場合、shutilモジュールのrmtree関数を使用する。
第1引数に指定したパスが示すディレクトリを削除する。
ディレクトリ内にファイルやディレクトリが含まれている場合は、一括削除する。
 shutil.rmtree(path, ignore_errors = False, onerror = None)
 import shutil
 
 path = './test/movie'
 shutil.rmtree(path)
ディレクトリの作成 / 削除 (pathlibモジュールの使用)
ディレクトリの作成 (pathlibモジュールの使用)
ディレクトリを新規作成する場合は、pathlibモジュールにあるPathクラスのmkdirメソッドを使用する。
省略可能な第1引数には、新規作成するディレクトリの権限を設定する。(省略された場合は、8進数で0o777が設定される)
省略可能な第2引数にTrueを指定する場合、中間ディレクトリを自動的に作成する。
省略可能な第3引数にTrueを指定する場合、新規作成するディレクトリが存在していてもエラーにはならない。
 Path.mkdir(mode=0o777, parents=False, exist_ok=False)
以下の例では、新規作成するディレクトリを示すパスからPathクラスのインスタンスを生成した後、mkdirメソッドを使用している。
mkdirメソッドは中間ディレクトリを自動的に作成するため、中間ディレクトリである./testディレクトリが存在しない場合は、
./testディレクトリを作成した後、指定のパスのディレクトリを作成する。
 import pathlib
 
 p = pathlib.Path('./test/back')
 p.mkdir(parents = True)
ディレクトリの削除 (pathlibモジュールの使用)
ディレクトリを削除する場合、pathlibモジュールにあるPathクラスのrmdirメソッドを使用する。
ただし、ディレクトリは空である必要がある。
削除するディレクトリが空ではない場合、例外OSErrorが発生する。
 Path.rmdir()
以下の例では、削除するディレクトリを示すパスからPathクラスのインスタンスを作成した後、rmdirメソッドを使用している。
 import pathlib
 
 p = pathlib.Path('./test/movie')
 p.rmdir()
ディレクトリの存在確認
指定したパスが示すディレクトリが存在するかどうかを確認する場合、os.pathモジュールのexists関数を使用する。
引数に指定したパスが存在する場合は、Trueを返す。
また、exists関数は、引数に指定したパスがファイルまたはディレクトリであっても存在する場合は、Trueを返すことに注意する。
 os.path.exists(path)
 import os
 import pathlib
 
 path1 = './test/address.txt'
 if os.path.exists(path1) :
    print(path1 + 'は存在します')
 else :
    print(path1 + 'は存在しません')
 
 path2 = './test/user.txt'
 if os.path.exists(path2) :
    print(path2 + 'は存在します')
 else :
    print(path2 + 'は存在しません')
 
 # 出力
 True
引数に指定されたパスにおいて、ファイルまたはディレクトリを判別するには、Pythonの基礎 - ファイル#ファイルとディレクトリの判別を参照すること。
ディレクトリの存在確認 (pathlibモジュールの使用)
指定したパスが示すディレクトリが存在するかどうかを確認する場合、pathlibモジュールにあるPathクラスのexistsメソッドを使用する。
パスが示すディレクトリが存在する場合は、Trueを返す。
また、Pathクラスのexistsメソッドは、引数に指定したパスがファイルまたはディレクトリであっても存在する場合は、Trueを返すことに注意する。
 Path.exists()
ディレクトリの存在を確認するには、まず、存在を確認するファイルのパスからPathクラスのインスタンスを生成した後、existsメソッドを使用する。
 import pathlib
 
 path1 = './test/address.txt'
 p1 = pathlib.Path(path1)
 if p1.exists() :
    print(path1 + 'は存在します')
 else :
    print(path1 + 'は存在しません')
 
 path2 = './test/user.txt'
 p2 = pathlib.Path(path2)
 if p2.exists() :
    print(path2 + 'は存在します')
 else :
    print(path2 + 'は存在しません')
ディレクトリ名の変更
ディレクトリ名を変更する場合は、osモジュールのrename関数を使用する。
 os.rename(src, dst, *, src_dir_fd=None, dst_dir_fd=None)
第1引数に指定したパスが示すディレクトリ名を、第2引数に指定したパスが示すディレクトリ名に変更する。
ディレクトリ名を変更する場合、変更前と変更後でディレクトリの親ディレクトリが異なっていても問題ない。
ただし、ディレクトリ名を変更する時、変更後の親ディレクトリが存在しない場合、例外FileNotFoundErrorが発生する。
 import os
 
 oldpath1 = './test/book'
 newpath1 = './test/memo'
 os.rename(oldpath, newpath)
Windows環境の場合、変更後のパスが既に存在する場合、例外FileExistsErrorが発生する。
 import os
 
 oldpath = './test/book'
 newpath = './back/memo'
 os.rename(oldpath, newpath)  # 既にmemoディレクトリが存在する場合は、例外FileExistsErrorが発生する
ディレクトリの変更 (pathlibモジュールの使用)
ディレクトリ名を変更する場合は、pathlibモジュールにあるPathクラスのrenameメソッドを使用する。
パスが示すディレクトリの名前を、引数に指定したパスが示すディレクトリ名に変更する。
ディレクトリ名を変更する場合、変更前と変更後でディレクトリの親ディレクトリが異なっていても問題ない。
ただし、ディレクトリ名を変更する時、変更後の親ディレクトリが存在しない場合、例外FileNotFoundErrorが発生する。
 Path.rename(target)
 import pathlib
 
 oldpath1 = pathlib.Path('./test/book')
 oldpath1.rename(pathlib.Path('./test/memo'))
Windows環境の場合、変更後のパスが既に存在する場合、例外FileExistsErrorが発生する。
 import pathlib
 
 oldpath = pathlib.Path('./test/book')
 oldpath.rename(pathlib.Path('./test/address'))  # 既にaddressディレクトリが存在する場合は、例外FileExistsErrorが発生する
条件に一致するファイル / ディレクトリの一覧の取得
同階層のファイル / ディレクトリの一覧の取得
指定した条件に一致するファイルやディレクトリの一覧を取得する場合は、globモジュールのglob関数を使用する。
 glob.glob(pathname, *, recursive=False)
第1引数に指定したパスとマッチするファイルおよびディレクトリを、リストとして取得する。
この時、パスには以下の特殊文字を指定することができる。
* : 0文字以上の任意の文字 ? : 1文字の任意の文字 [abc] : 括弧の中のいずれかの文字
*は、0文字以上の任意の文字とマッチする。
例えば、*.txtと指定する場合、a.txtやmemo.txt等の"0文字以上の任意の文字列" + ".txt"に一致するファイルおよびディレクトリの一覧を取得する。
以下の例では、末尾が.jpgのファイルおよびディレクトリの一覧を取得している。
 import glob
 
 for name in glob.glob('./test/*'):
    print(name)
 
 # 出力
 ./test/img
 ./test/movie
 ./test/pen.jpg
以下の例では、bから始まるファイルおよびディレクトリの一覧を取得している。
 import glob
 
 for name in glob.glob('./test/b*'):
    print(name)
 
 # 出力
 ./test/back
 ./test/book.png
?は、1文字の任意の文字とマッチする。
例えば、?.txtと指定する場合、a.txtやc.txt等の"1文字の任意の文字" + ".txt"と一致するファイルやディレクトリの一覧を取得する。
2文字以上のabc.txt等にはマッチしない。
以下の例では、3文字の任意の文字で始まり、末尾が.txtのファイルおよびディレクトリの一覧を取得している。
 import glob
 
 for name in glob.glob('./test/???.txt'):
    print(name)
 
 # 出力
 ./test/cup.txt
 ./test/pen.txt
[]は、括弧の中に記述した文字のいずれか1文字とマッチする。
例えば、199[789].txtと指定する場合、1997.txt、1998.txt、1999.txtと一致するファイルやディレクトリの一覧を取得する。
1文字ではない19978.txt等にはマッチしない。
また、[3-6]や[a-e]等のようにハイフンを記述することにより、文字の範囲を指定することができる。
[3-6]は[3456]と等価、[a-e]は[abcde]と等価である。
以下の例では、最初にaからeまでの文字で始まり、末尾が.txtのファイルおよびディレクトリの一覧を取得している、
さらに、fからzまでの文字で始まり、末尾が.txtのファイルおよびディレクトリの一覧を取得している。
 import glob
 
 for name in glob.glob('./test/[a-e]*.txt'):
    print(name)
 
 for name in glob.glob('./test/[c-z]*.txt'):
    print(name)
 
 # 出力
 ./test/book.txt
 ./test/environment.txt
 ./test/flavor.txt
 ./test/pen.txt
glob関数において、特殊文字である*、?、[]をを単なる文字として扱う場合は、[]で囲んで記述する。
例えば、?を文字として扱う場合は、[?]と記述する。
 import glob
 
 for name in glob.glob('./test/*[?]*'):
    print(name)
 
 # 出力
 ./test/ab?cd
再帰的にファイル / ディレクトリの一覧の取得
glob関数において、第2引数にTrueを指定することにより、特殊文字**が使用できる。
パスの指定において、**を使用することにより、全てのファイルおよび0個以上のディレクトリとサブディレクトリにマッチする。
 glob.glob(pathname *, recursive = False)
例えば、パスを./**/*.txtと指定する場合、a.txtやmemo.txt等の同階層のディレクトリにあるファイルの他に、
./doc/b.txtや./html/back/2020/report.txt等のサブディレクトリにあるファイルも対象となる。
以下の例では、サブディレクトリを再帰的に検索して条件に一致するファイルを取得している。
 import glob
 
 for name in glob.glob('./test/**/*', recursive = True):
    print(name)
 
 # 出力
 ./test/img
 ./test/movie
 ./test/pen.txt
 ./test/back
 ./test/back/2020.txt
条件に一致するファイルやディレクトリをイテレータとして取得
glob関数は、条件に一致する全てのファイルやディレクトリが含まれるリストが取得できるが、
iglob関数は、条件に一致するファイルやディレクトリに順にアクセスできるイテレータを取得することができる。
 glob.iglob(pathname *, recursive = False)
多くのファイルやディレクトリが一致するような場合は、全ての結果をまとめて取得するのではなく、逐一取得するイテレータを使用する方が実行速度が早い。
 import glob
 
 for name in glob.iglob('./test/**/*.txt', recursive=True):
    print(name)
 
 # 出力
 ./test\book.txt
 ./test\cup.txt
 ./test\pen.txt
 ./test\back\2019.txt
 ./test\back\2020.txt
 ./test\back\old\2017.txt
条件に一致するファイル / ディレクトリの一覧の取得 (pathlibモジュールの使用)
同階層のファイル / ディレクトリの一覧の取得 (pathlibモジュールの使用)
指定した条件に一致するファイルやディレクトリの一覧を取得する場合、pathlibモジュールにあるPathクラスのglobメソッドを使用する。
 Path.glob(pattern)
Pathクラスのglobメソッドは、パスが示すディレクトリおよびそのサブディレクトリに含まれるファイルやディレクトリにおいて、
第1引数に指定したパターンとマッチするファイルやディレクトリへ順にアクセスできるイテレータを取得する。
この時、パターンには以下の特殊文字を指定することができる。
* : 0文字以上の任意の文字 ? : 1文字の任意の文字 [abc] : 括弧の中のいずれかの文字
*は、0文字以上の任意の文字とマッチする。
例えば、*.txtと指定する場合、a.txtやmemo.txt等の"0文字以上の任意の文字列" + ".txt"に一致するファイルおよびディレクトリの一覧を取得する。
以下の例では、末尾が.jpgのファイルおよびディレクトリの一覧を取得している。
 import pathlib
 
 p = pathlib.Path('./test')
 for name in p.glob('*.txt'):
    print(name)
 
 # 出力
 ./test/a.jpg
 ./test/cup.jpg
 ./test/pen.jpg
以下の例では、bから始まるファイルおよびディレクトリの一覧を取得している。
 import pathlib
 
 p = pathlib.Path('./test')
 for name in p.glob('b*'):
    print(name)
 
 # 出力
 ./test/back
 ./test/back/book.png
?は、1文字の任意の文字とマッチする。
例えば、?.txtと指定する場合、a.txtやc.txt等の"1文字の任意の文字" + ".txt"と一致するファイルやディレクトリの一覧を取得する。
2文字以上のabc.txt等にはマッチしない。
以下の例では、3文字の任意の文字で始まり、末尾が.txtのファイルおよびディレクトリの一覧を取得している。
 import pathlib
 
 p = pathlib.Path('./test')
 for name in p.glob('???.txt'):
    print(name)
 
 # 出力
 ./test/cup.txt
 ./test/pen.txt
[]は、括弧の中に記述した文字のいずれか1文字とマッチする。
例えば、199[789].txtと指定する場合、1997.txt、1998.txt、1999.txtと一致するファイルやディレクトリの一覧を取得する。
1文字ではない19978.txt等にはマッチしない。
また、[3-6]や[a-e]等のようにハイフンを記述することにより、文字の範囲を指定することができる。
[3-6]は[3456]と等価、[a-e]は[abcde]と等価である。
以下の例では、最初にaからeまでの文字で始まり、末尾が.txtのファイルおよびディレクトリの一覧を取得している、
さらに、fからzまでの文字で始まり、末尾が.txtのファイルおよびディレクトリの一覧を取得している。
 import pathlib
 
 p = pathlib.Path('./test')
 for name in p.glob('[a-e]*.txt'):
    print(name)
 
 for name in p.glob('[c-z]*.txt'):
    print(name)
 
 # 出力
 ./test/book.txt
 ./test/environment.txt
 ./test/flavor.txt
 ./test/pen.txt
Pathクラスのglobメソッドにおいて、特殊文字である*、?、[]をを単なる文字として扱う場合は、[]で囲んで記述する。
例えば、?を文字として扱う場合は、[?]と記述する。
再帰的にファイル / ディレクトリの一覧の取得 (pathlibモジュールの使用)
Pathクラスのglobメソッドにおいて、パスの指定時に**を使用することにより、全てのファイルおよび0個以上のディレクトリとサブディレクトリにマッチする。
これは、globモジュールのglob関数とは異なり、Pathクラスのglobメソッドはデフォルトでサブディレクトリを再帰的に検索する。
例えば、パスを./**/*.txtと指定する場合、a.txtやmemo.txt等の同階層のディレクトリにあるファイルの他に、
./doc/b.txtや./html/back/2020/report.txt等のサブディレクトリにあるファイルも対象となる。
以下の例では、サブディレクトリを再帰的に検索して条件に一致するファイルを取得している。
 import pathlib
 
 p = pathlib.Path('./test')
 for name in p.glob('**/*.txt'):
    print(name)
 
 # 出力
 ./test\book.txt
 ./test\cup.txt
 ./test\pen.txt
 ./test\back\2020.txt
 ./test\back\old\2017.txt
ディレクトリに含まれるファイルとディレクトリの一覧の取得
ファイルとディレクトリの一覧の取得
指定したディレクトリに含まれるファイルとディレクトリの一覧を取得する場合、osモジュールのlistdir関数を使用する。
引数にディレクトリを指定する時、そのディレクトリに含まれるファイル名とディレクトリ名が格納されたリストを返す。
ファイル名とディレクトリ名は、区別せずにリストに格納される。
 os.listdir(path='.')
 import os
 
 path = './test/'
 filelist = os.listdir(path)
 print(filelist)
 
 # 出力
 ['address.txt', 'doc', 'img', 'name.txt']
なお、引数に指定したディレクトリ名と取得したファイル名およびディレクトリ名を結合することによりパスを取得できるが、
os.pathモジュールのjoin関数を使用した方が簡単である。
複数のパスが格納されているリストを第2引数に指定することにより、ディレクトリの区切り文字(/または\)が自動的に付加されて結合した結果を返す。
 os.path.join(path, *paths)
 import os
 
 path = './test/'
 filelist = os.listdir(path)
 
 for f in filelist:
    print(f)
    print(os.path.join(path, f))
ファイルとディレクトリの判別
指定したパスにおいて、ファイルまたはディレクトリを判別する場合、os.pathモジュールのisfile関数およびisdir関数を使用する。
isfile関数は、引数に指定したパスが存在、かつ、ファイルの場合はTrueを返す。
 os.path.isfile(path)
isdir関数は、引数に指定したパスが存在、かつ、ディレクトリの場合はTrueを返す。
 os.path.isdir(path)
isfile関数とisdir関数は、ファイルおよびディレクトリが存在しない場合はFalseを返す。
 import os
 
 path = './test/'
 print(os.path.isfile(path))
 print(os.path.isdir(path))
 
 path = './test/address.txt'
 print(os.path.isfile(path))
 print(os.path.isdir(path))
 
 # 出力
 False
 True
 True
 False
以下の例では、./testディレクトリに含まれるファイルとディレクトリの一覧を取得して、ファイルの場合は[F] + ファイル名、ディレクトリの場合は[D] + ディレクトリ名を出力している。
 import os
 
 path = './test/'
 filelist = os.listdir(path)
 
 for f in filelist:
    if os.path.isfile(os.path.join(path, f)):
       print('[F]:' + f)
    else:
       print('[D]:' + f)
ファイルおよびディレクトリに関する情報も併せて取得する
指定したディレクトリに含まれるファイルとディレクトリの一覧を取得する別の方法として、osモジュールのscandir関数を使用する。
osモジュールのscandir関数は、引数にパスを指定する時、そのパスに含まれるファイルまたはディレクトリに関する情報を持つos.DirEntryオブジェクトのイテレータを返す。
この情報は、ファイル名やディレクトリ名、ファイルまたはディレクトリの判別、ファイルのサイズ、タイムスタンプ等の情報を持つ。
os.DirEntryクラスのname属性を参照することによりファイル名またはディレクトリ名を取得することができ、path属性を参照することによりパスを取得することができる。
 os.scandir(path = '.')
以下の例では、イテレータから要素を1つ取り出してファイル名とパスをそれぞれ出力している。
 import os
 
 path = './test/'
 itr = os.scandir(path)
 f = next(itr)
 
 print(f.name)
 print(f.path)
 
 # 出力
 address.txt
 ./test/address.txt
また、os.DirEntryクラスのis_fileメソッド、および、is_dirメソッドを使用することにより、ファイルおよびディレクトリを判別することができる。
os.DirEntryクラスのis_fileメソッドは、ファイルが存在、かつ、ファイルまたはファイルへのシンボリックリンクである場合にTrueを返す。
 is_file(*, follow_symlinks = True)
os.DirEntryクラスのis_fileメソッドは、ディレクトリが存在、かつ、ディレクトリまたはディレクトリへのシンボリックリンクである場合にTrueを返す。
 is_dir(*, follow_symlinks = True)
以下の例では、イテレータから要素を1つ取り出して、ファイル名またはディレクトリ名を出力、および、ファイルまたはディレクトリの判別をしている。
 import os
 
 path = './test/'
 itr = os.scandir(path)
 f = next(itr)
 
 print(f.name)
 print(f.is_file())
 print(f.is_dir())
 
 # 出力
 address.txt
 True
 False
以下の例では、./testディレクトリに含まれるファイルとディレクトリの一覧を取得して、
ファイルの場合は[F] + ファイル名 + パス、ディレクトリの場合は[D] + ディレクトリ名 + パスを出力している。
 import os
 
 path = './test/'
 for i in os.scandir(path):
    if i.is_file():
       print('[F]:' + i.name + ' ' + i.path)
    else:
       print('[D]:' + i.name + ' ' + i.path)