Pythonを使ったディレクトリ(フォルダ)やファイルを操作を、この記事1本にまとめました。
かなりの大ボリュームになってしまいましたが、この記事でお伝えしていることは大きく次の5つだけです。
- 作成
- 削除
- 情報の取得・加工
- 移動
- 存在確認
本記事の内容だけで、Pythonのディレクトリ操作はかなり網羅できているはずです。逆引き辞書的にお使いいただくことを想定して作りました。
この後に設置した目次がリンクになっています。調べたい内容をクリックしてご活用ください。
ディレクトリの作成
ディレクトリの作成には、os
やpathlib
などのライブラリを使います。
なお、os
もpathlib
も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
です。そのため第二引数に何も渡さないと、同名のフォルダがあるとエラーが表示されます。
再帰的にフォルダを作成したい場合
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()
で実体として作成しました。
フォルダを再帰的に作成
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)
ディレクトリの削除
ディレクトリを削除するには、os
やshutil
などのライブラリを使います。
なお、os
もshutil
も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()
を使ってディレクトリの中身を空にする方法
ディレクトリの中身だけを空にするには、次の方法が手っ取り早いです。
shutil.rmtree()
でフォルダごと削除する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 — 雑多なオペレーティングシステムインターフェースos.removedirs('foo/bar/baz')
では最初にディレクトリ'foo/bar/baz'
を削除し、次に'foo/bar'
さらに'foo'
をそれらが空ならば削除します。末端のディレクトリが削除できなかった場合にはOSError
が送出されます。
os.rmdir()よりも使う機会は少ないと思いますが、こちらもサンプルコードをのせておきます。
import os
os.removedirs("folder/1/2/3")
まず3が空なら削除、続いて2が空なら削除、さらに1が空なら削除、最後にfolderが空なら削除という流れです。
フォルダの中に何らかのファイルが入っていればエラーになります。
ディレクトリ情報の取得
ディレクトリ情報の取得には、os
やglob
などのライブラリを使います。
なお、os
もglob
も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()
を使います。
簡単な流れは次の通りです。
chdir()
で現在のディレクトリを移動する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つの方法があります。
- エスケープシーケンスを使う
- raw文字列を使う
- 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のディレクトリ操作は大きく次の通り。
- 作成
- 削除
- 情報の取得
- 取得した情報の加工
- 存在確認
普段基本的なコードを書いていく上では、これだけ知っていれば十分だと思います。
記事内で誤植などがありましたら、コメント欄よりお知らせいただけると大変助かります。
コメント