【保存版】Pythonを使ったディレクトリ・ファイル操作のすべて

Pythonを使ったディレクトリ(フォルダ)やファイルを操作を、この記事1本にまとめました。

かなりの大ボリュームになってしまいましたが、この記事でお伝えしていることは大きく次の5つだけです。

本記事の内容
  1. 作成
  2. 削除
  3. 情報の取得・加工
  4. 移動
  5. 存在確認

本記事の内容だけで、Pythonのディレクトリ操作はかなり網羅できているはずです。逆引き辞書的にお使いいただくことを想定して作りました。

この後に設置した目次がリンクになっています。調べたい内容をクリックしてご活用ください。

本記事では「フォルダ」と「ディレクトリ」を同じ意味で使っています。
両者は厳密には異なり、違いが気になる方はこちらの記事が参考になると思います。
» 参考:「ディレクトリ」と「フォルダ」の違いと共通点

目次

ディレクトリの作成

ディレクトリの作成には、ospathlibなどのライブラリを使います。

なお、ospathlibもPythonに標準で装備されているので$pip installは不要です。

【推奨】os.makedirs()を使う方法

非常に使い勝手の良いのがos.makedirs()です。

基本

もっともシンプルなコードは次の通りです。

import os

new_folder = "new_folder_name"
os.makedirs(new_folder)

os.makedirs()の引数には、作りたいディレクトリ名を渡します。今回の例では"new_folder"というディレクトリがpyファイルと同じ階層に作られます。

ただし、すでにnew_folderという名前のディレクトリがある場合にエラーになってしまいます。

これを避けるためには、次に紹介するexist_ok=Trueというものが用意されています。

同名のディレクトリがあってもエラー表示しない

同名のディレクトリがすでに存在してもエラーにしたくない場合は、exist_ok=Trueを使います。つまりエラーが無視されます。

使い方はos.makedirs()の第二引数としてexist_ok=Trueを渡すだけ。

import os

new_folder = "new_folder_name"
os.makedirs(new_folder, exist_ok=True)

余談ですが、os.makedirs()のデフォルトはexist_ok=Falseです。そのため第二引数に何も渡さないと、同名のフォルダがあるとエラーが表示されます。

exist_okはPython3.2以降で有効です。それ以前のバージョンでは使えません。

再帰的にフォルダを作成したい場合

os.makedirs()は再帰的なフォルダ作成に対応しています。

再帰的というのは、深い階層まで一気にフォルダを作れることをいいます。具体例を見た方がわかりやすいかもしれません。

import os

os.makedirs("new_folder/1/2", exist_ok=True)

上記のように書くだけで、new_folderの下に1が、その下に2が作成されます。

Python3.2より前のバージョンでexist_okの機能を実装したい

exist_okが使えない場合には、次の二つの方法で実装できます。

  • tryを使う方法
  • os.path.isdir()を使う方法

まずは、tryを使う方法です。コードを確認しましょう。

import os

new_folder = "new_folder_name"
try:
    os.makedirs(new_folder)
except FileExistsError:
    pass

原則はtry文の中だけ(5行目)を実行しますが、try文でエラーがあればexcept内(7行目)を実行します。

つまり、new_folderが存在するとtry内でエラーが発生するので、except内のpass(=何もしない)が実行されます。

別の方法としてos.path.isdir()でも可能です。

import os

new_folder = "new_folder_name"
if not os.path.isdir(new_folder)
    os.makedirs(new_folder)

前もって4行目でnew_folderが存在するかを判定して、フォルダがなければos.makedirs()を実行します。

【非推奨】os.mkdir()を使う方法

pathlib.Path()でフォルダ作成する方法

pathlib.Path()を使うことで、フォルダをオブジェクトとして操作できます。

基本

基本のコードは次の通りです。

import pathlib

new_folder = "new_folder_name"
p = pathlib.Path(new_path)
p.mkdir()

os.makedirs()との違いは4行目ですね。ここではpathlib.Path(new_path)pにとおくことでnew_pathを定義しています。(正確にはインスタンス化と呼ばれるものです)ここではnew_pathの存在を定義しただけなので、実際にはフォルダは作成されません。

実際にフォルダが作成されるのは5行目です。
4行目でpとして定義されたフォルダをmkdir()で実体として作成しました。

インスタンス化をより詳しく知りたい方は参考記事もどうぞ。…とはいえ、難解なので余力があればでOKです。
» 参考:Python クラスについて

フォルダを再帰的に作成

pathlib.Path()でも、os.makedirs()のように再帰的にフォルダを作成できます。つまり、中間ディレクトリも一気に作れます。(詳細はこちら

方法はmkdir()の引数としてparents=Trueを渡すだけです。

import pathlib

new_folder = "new_folder_name"
p = pathlib.Path(new_path)
p.mkdir(parents=True)

同名のディレクトリがあってもエラー表示しない

mkdir()の引数にexist_ok=Trueを渡すと、すでにフォルダが存在していてもエラーを表示しません。

import pathlib

new_folder = "new_folder/1/2/3"
p = pathlib.Path(new_folder)
p.mkdir(parents=True, exist_ok=True)

ディレクトリの削除

ディレクトリを削除するには、osshutilなどのライブラリを使います。

なお、osshutilもPythonに標準で装備されているので$pip installは不要です。

shutil.rmtree()でフォルダごとまるっと削除する

shutil.rmtree()を使うと、指定したフォルダとその中にあるファイルを丸ごと削除できます。

import shutil

new_folder = "new_folder_name"
shutil.rmtree(new_folder)

サンプルコードを試す場合は、os.makedirs()などでpyファイルと同じ階層にnew_folder_nameというフォルダを作っておきましょう。

shutil.rmtree()os.makedirs()を使ってディレクトリの中身を空にする方法

ディレクトリの中身だけを空にするには、次の方法が手っ取り早いです。

  1. shutil.rmtree()でフォルダごと削除する
  2. os.makedirs()で新たに空のフォルダを作成する

コードを確認してみましょう。

import shutil
import os

new_folder = "new_folder_name"
shutil.rmtree(new_folder)
os.makedirs(new_folder)

フォルダ内のファイルだけを削除しようとすると結構大変なので、原始的ですがこの方法がおすすめです。

フォルダの中身が「空」の場合のみ削除するos.rmdir()

os.rmdir()を使うと、指定したフォルダが空の場合のみ削除します。

import os

new_folder = "new_folder_name"
os.rmdir(new_folder)

もしフォルダ内に何かしらのファイルが存在した場合にはエラーになります。

エラーでプログラムを止めたくない場合は、try文を使うと良いでしょう。

import os

new_folder = "new_folder_name"
try:
    os.rmdir(new_folder)
except:
    pass

if文で条件分岐させても良いかもしれません。

中間フォルダも空ならまとめて削除するos.removedirs()

少し挙動が分かりにくいので、osの公式ドキュメントから具体例を引用します。

例えば、 os.removedirs('foo/bar/baz') では最初にディレクトリ 'foo/bar/baz' を削除し、次に 'foo/bar' さらに 'foo' をそれらが空ならば削除します。末端のディレクトリが削除できなかった場合には OSError が送出されます。

出典:os — 雑多なオペレーティングシステムインターフェース

os.rmdir()よりも使う機会は少ないと思いますが、こちらもサンプルコードをのせておきます。

import os

os.removedirs("folder/1/2/3")

まず3が空なら削除、続いて2が空なら削除、さらに1が空なら削除、最後にfolderが空なら削除という流れです。

フォルダの中に何らかのファイルが入っていればエラーになります。

ディレクトリ情報の取得

ディレクトリ情報の取得には、osglobなどのライブラリを使います。

なお、osglobもPythonに標準で装備されているので$pip installは不要です。

glob.glob()を使ったディレクトリ情報の取得

globには次のようなメリットがあります。

  • サブディレクトリまでたどれる
  • ワイルドカードが使える
  • フルパスとしてリストが取得できる

使い勝手の良いライブラリなので、僕も頻繁に利用しています。

基本

使い方は、glob.glob()の引数としてリストを取得したいディレクトリをフルパスで指定します。

import glob
import os

current_dir = os.getcwd()
files_list = glob.glob(current_dir + "/*")
print(files_list)

4行目では、Pythonの実行ファイルがあるディレクトリをフルパスで取得しています。(os.getcwd()についてはこちら

5行目では、current_dirの中にあるフォルダやファイルをすべて取得しています。こちらは現在のパスに加えて/*と書くことで、配下にあるものをすべて取得します。

*はワイルドカードの一種でして、「0文字以上の文字列」を表します。何かしらのファイルやフォルダがあればヒットしてリストとして返してくれるというわけですね。

ワイルドカード役割
*0文字以上の任意の文字列
?1文字の任意の文字列
[]特定の文字列
ex: [0-9]だと0~9の数字を指す
ワイルドカード

なお、*?[]をワイルドカードではなく文字列として使いたい場合は、[]で囲います。例えば[*]のような感じですね。これをエスケープといいます。

glob.glob()を使って拡張子で絞り込む

ワイルドカードを上手に使うと、取得するファイルを拡張子で絞り込みできます。

import glob
import os

current_dir = os.getcwd()
files_list = glob.glob(current_dir + "/*.xlsx")
print(files_list)

5行目のコードを少しだけ変更しました。/*.xlsxとすることで、フォルダ内のエクセルファイルだけをリストにすることができます。

これを/*.pdfにしたり/*.pyにしたりすることで、収集する対象のファイルを自在に変えられます。

glob.glob()を使ってサブディレクトリの情報も走査する

こちらも発展系として、glob.glob()を使ってサブディレクトリの情報も取得できます。

import glob
import os

current_dir = os.getcwd()
files_list = glob.glob(current_dir + "**/*", recursive=True)
print(files_list)

5行目を一部変更することで、サブディレクトリを全て検索対象に含めることができます。

ここでのキモはrecursive=Trueとした上で/**/ のようにアスタリスクが二つ連続で並んでいること。これによって、配下にあるフォルダをすべてクロールしてくれるようになります。

さらに拡張子で絞りたい場合には、"**/*.xlsx"とすればOKです。

pathlib.Path()を使ったサブフォルダも含めた全ファイル・フォルダの走査

一つ前でご紹介したglob.glob(path/**/*", recursive=True)のようなことが、pathlib.Path()でも実装できます。

この場合はrglob()メソッドというものを使います。

import pathlib

path = pathlib.Path(".").rglob("*")
path_list = [str(p) for p in path]
print(path_list)

pathlib.Path()の場合はrglob()で抽出すると抽出したパス名がPosixPath形式でリストに格納されます。

そのため、基本的にはglob.glob()の方が使い勝手が良いような気がします。

os.listdir()を使ってディレクトリの内容を取得する方法

os.listdir()を使うと、ディレクトリ内の情報をリストとして取得できます。

基本

os.listdir()の引数にディレクトリのパスを指定することで、その中にあるディレクトリ名やファイル名をリスト形式で返してくれます。

import os

path = "."
dir_list = os.listdir(path)
print(dir_list)

フルパスではなく、あくまでファイル名やフォルダ名だけが返ってくる点は注意です。

また3行目について補足です。.とすることで、Pythonの実行ファイル(pyファイル)と同じ階層のディレクトリを示せます。つまり、上記を実行することで実行ファイル(.py)と、同じ階層にあるフォルダ名、ファイル名がリストとして返ってきます。

もし、一つ上のディレクトリを指したいなら..のように記入します。

ファイル名だけを抽出したい場合はos.path.isfile()とループを使う

単にos.listdir()を使うと、フォルダもファイルもごった煮のリストが返ってきてしまいます。

とはいえ、ファイル名のみを抽出したい場合もありますよね。その場合は、os.path.isfile()でファイルかどうかの判定をしつつループでリストに格納し直します。

import os

path = "."
dir_list = os.listdir(path)
file_list = [f for f in dir_list if os.path.isfile(os.path.join(path, f))]
print(file_list)

5行目は「リスト内包表記」と呼ばれる記法です。ループ処理を1行で表せることと、処理速度が早いため覚えておくと便利。

ディレクトリ名だけを抽出したい場合はos.path.dir()とループを使う

フォルダ名のみを抽出したい場合も、ファイル名のみの場合と考え方は同じです。os.path.isfile()の代わりにos.path.dir()を使えばOKです。

import os

path = "."
dir_list = os.listdir(path)
file_list = [f for f in dir_list if os.path.isdir(os.path.join(path, f))]
print(file_list)

os.getcwd()で現在のディレクトリをフルパスで取得

現在のディレクトリを取得する場合、os.getcwd()を使います。戻り値はフルパスです。

import os

current_path = os.getcwd()
print(current_path)

余談ですが、cwdは”Current Working Directory” の略です。

os.chdir()で1つ上、2つ上の階層のディレクトリをフルパスで取得

一つ上・一つ下のディレクトリをフルパスで取得する場合は、os.chdir()を使います。

簡単な流れは次の通りです。

  1. chdir()で現在のディレクトリを移動する
  2. getcwd()で移動後のフルパスを取得する

コードを確認してみましょう。

import os

os.chdir("..")   # 一つ上の階層に移動
higher_path = os.getcwd()
print(higher_path)

chdir()はターミナルの操作でいうところのcd(Change Directory)のようなものです。..とすることで、一つ上の階層のディレクトリに移動できます。

二つ上のディレクトリに行きたければ...とします。

os.environ["HOME"]でホーム(ルート)ディレクトリを取得

os.environ["HOME"]でホームディレクトリを取得できます。

import os

home = os.environ['HOME']
print(home)

os.path.basename()でファイル名を抽出する

ファイル名のみを抽出するには、os.path.basename()を使います。

拡張子を含むファイル名を取得する場合

拡張子を含むファイル名を取得するには、単にos.path.basename()を使えば良いので簡単です。

サンプルコードは次のとおり。

import os

base_name = os.path.basename(full_path)
print(base_name)

こちらで「ファイル名 + 拡張子」の形式で文字列を取得できます。

拡張子なしのファイル名を取得する場合

また、os.path.splitext()との組み合わせれば拡張子なしのファイル名を取得することも可能です。

import os

base_name = os.path.basename(full_path)
file_name = os.path.splitext(base_name)[0]
print(base_name)

os.path.splitext()は、文字列の一番右にある.(ドット)を境に配列の0番目と1番目に分けてくれます。すなわち、0番目にはファイル名が、1番目には拡張子名が格納されるわけですね。

そのため、4行目のコードでは配列から0番目(つまりファイル名のみ)を指定してfile_nameという変数に格納しているというわけです。

これで拡張子なしでファイル名の取得ができます。

ディレクトリ・ファイルのコピーと移動

ディレクトリやファイルの移動・コピーはshutilを使います。

shutil.copy()でディレクトリやファイルをコピーする

ディレクトリやファイルをコピーするにはshutil.copy()を使います。

第一引数にはコピーしたいものを、第二引数にはコピー先を指定します。

import shutil

shutil.copy(from_filename, to_directry)

第二引数にディレクトリを渡した場合は、第一引数で指定したファイル名と同じファイル名でコピーされます。

ただし、第一引数としてファイルが入っているディレクトリを指定するとエラーになってしまうので、次に紹介するshutil.copytree()を使います。

フォルダを中身ごとコピーしたい場合はshutil.copytree()を使う

コピー元としてファイルの入ったフォルダを選択する場合は、shutil.copytree()を使います。

import shutil

shutil.copytree(from_directory, to_directory)

shutil.move()でファイル・フォルダを移動する

ファイルやフォルダの移動にはshutil.move()を使います。

import shutil

shutil.move(from_path, to_path)

ディレクトリもファイルもこれ一つで操作できます。

ディレクトリ・ファイルの存在判定

ディレクトリやファイルの存在確認はosを使います。

主な用途は、何かしらのプログラムを動かす前にディレクトリやファイルが存在するという感じです。

os.path.exist()でディレクトリまたはファイルの存在を確認する

ディレクトリまたはファイルの存在確認にはos.path.exist()を使います。

引数には、存在確認をしたいフォルダやファイルのパスを渡します。

import os

# フォルダの存在確認
folder_path_exist = os.path.exist(folder_path)
print(folder_path_exist)
# ファイルの存在確認
file_path_exist = os.path.exist(file_path)
print(file_path_exist)

存在していればTrue、なければFalseを返します。

os.path.isfile()でファイルの存在確認をする

ファイルの存在確認をしたい場合、os.path.isfile()を使います。

import os

file_path_exist = os.path.isfile(file_path)
print(file_path_exist)

引数にはファイル名を渡すようにしましょう。もし引数にディレクトリを指定するとFalseとなります。

os.path.isdir()でディレクトリの存在確認をする

フォルダの存在確認をする場合は、os.path.isdir()を使います。

import os

folder_path_exist = os.path.isdir(folder_path)
print(folder_path_exist)

引数にはディレクトリ名を渡すようにしましょう。もし引数にファイル名を指定するとFalseとなります。

ディレクトリやファイルに関する豆知識

これまでご紹介してきたこと以外で知っておくと便利な豆知識をまとめました。

パスの区切り文字は/(スラッシュ)か\(バックスラッシュ)か

パスの区切り文字がWindowsとMacで異なります。

  • Mac:/を使います。例:/Users/nameUser/Desktop/など
  • Windows:\を使います。例:C:\ProgramFiles\karochoa\など

ここで問題になるのが、Windowsの区切り文字で使う\(バックスラッシュ)です。というのも、\(バックスラッシュ)と他の文字との組み合わせで特定の意味を持ってしまうことがあるからです。

例えば次のような組み合わせですね。

\との組み合わせコードの意味
\n改行
\tタブ
バックスラッシュと文字の組み合わせ

これらの不都合を回避するには、次の3つの方法があります。

  1. エスケープシーケンスを使う
  2. raw文字列を使う
  3. Windowsでも/を使う

Windowsで区切り文字が原因でエラーになった際には、次のいずれかを試してみてください。

エスケープシーケンスを使う

\を1文字多く入力することで回避でき、これをエスケープシーケンスといいます。

例えば\numberとだけ入力すると最初の二文字\nが改行の意味になってしまいます。これをすべてそのままの文字として認識させるには、\\numberとします。

raw文字列を使う

raw文字列とは、文字列を表す"文字列"をの前にrを記述します。つまり、書き方としてはr"文字列"のようになります。サンプルコードを確認してみましょう。

# raw文字列を使った方法
path = r"C:\ProgramFiles\number\"

先頭にrをつけるだけで、回避できます。

実はWindowsでも/(スラッシュ)が使える

実は、WindowsでもMacと同様に/(スラッシュ)区切りが使えます。

「だったらWindowsでも/(スラッシュ)区切りでコードを書けばいいじゃん」とも思えますが、右クリックからパスのコピーをした際などは\(バックスラッシュ)となってしまいます。こうなると、/(スラッシュ)と\(バックスラッシュ)が混在してしまう。

そのため僕がWindows環境でコードを書く際には、エスケープシーケンスやraw文字列を使いつつ\(バックスラッシュ)を使うことがほとんどです。

まとめ

ここまでPythonのディレクトリ操作をまとめてきました。

冒頭の繰り返しになりますが、本記事でご紹介したPythonのディレクトリ操作は大きく次の通り。

  1. 作成
  2. 削除
  3. 情報の取得
  4. 取得した情報の加工
  5. 存在確認

普段基本的なコードを書いていく上では、これだけ知っていれば十分だと思います。

記事内で誤植などがありましたら、コメント欄よりお知らせいただけると大変助かります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

かろちょあのアバター かろちょあ Pythonプログラマー

業務効率化やスクレイピングを専門に活動しているPythonプログラマーです。
Microsoft Office製品のほか、幅広い分野で自動化のお手伝いをしています。

コメント

コメントする

目次
閉じる