Pythonには、このタスクを支援するための組み込みのライブラリオブジェクトと関数のセットがあります。
このチュートリアルでは、Pythonでファイルやディレクトリが空かどうかをチェックする方法を学びます。
ファイルとディレクトリの見分け方
パスが空かどうかを調べたいとき、それがファイルなのかディレクトリなのかを知っておくと、使用するアプローチに影響するからです。
例えば、ローカルのディレクトリとファイルを識別する2つのプレースホルダ変数 dirpath
と filepath
があるとしましょう。
dirpath = '/mnt/f/code.books/articles/python'
filepath = '/mnt/f/code.books/articles/python/code/file_dir.py'
os.pathの使用
Python は os
モジュールを提供しています。
これはオペレーティングシステムを操作するための関数、オブジェクト、定数からなる Python の標準パッケージです。
os.pathは、ファイルとディレクトリを簡単に区別するための
isfile()と
isdir()` 関数を提供します。
import os
dirpath = '/mnt/f/code.books/articles/python'
filepath = '/mnt/f/code.books/articles/python/code/file_dir.py'
os.path.isfile(dirpath) # False
os.path.isdir(dirpath) # True
os.path.isfile(filepath) # True
os.path.isdir(filepath) # False
これらの関数は両方とも Boolean
値を返します。
パスリブの使用
Python 3.4 では、ファイルシステムを操作するためのオブジェクト指向のインターフェイスを提供する pathlib
モジュールが導入されました。
pathlibは
osや
os.path` と比較して、ファイルシステムを簡単に操作することができます。
pathlibモジュールの
Pathクラスは、引数としてパスを受け取り、
Path` オブジェクトを返します。
このオブジェクトは、メソッドや属性を用いて簡単にクエリやチェイン処理を行うことができます。
from pathlib import Path
dirpath = '/mnt/f/code.books/articles/python'
filepath = '/mnt/f/code.books/articles/python/code/file_dir.py'
Path(dirpath).is_file() # False
Path(dirpath).is_dir() # True
Path(filepath).is_file() # True
Path(dirpath).is_file() # False
ここでは、 Path
オブジェクトがファイルかディレクトリであるかどうかを調べています。
ファイルが空かどうか確認する
空ファイル(ゼロバイトファイル)とは、データや内容を一切含んでいないファイルのことです。
ファイルの種類は問いません。
特定のファイル(音楽ファイルなど)は、データがなくてもメタデータ(作者など)が含まれている場合があります。
このようなファイルは、空ファイルとはみなされません。
LinuxやMacOSでは、空ファイルを素早く作成することができます。
$ touch emptyfile
または、Windowsで。
$ type nul > emptyfile
ここで、0 バイトの空のファイルと 1 バイトの空のファイルを指す変数 emptyfile
と nonemptyfile
を定義しておこう。
emptyfile = '/mnt/f/code.books/articles/python/emptyfile'
nonemptyfile = '/mnt/f/code.books/articles/python/onebytefile'
これらのファイルの種類とサイズを見てみましょう。
$ ls -l
-rwxrwxrwx 1 root root 0 Sep 10 18:06 emptyfile
-rwxrwxrwx 1 root root 1 Sep 10 18:08 onebytefile
$ file emptyfile
emptyfile: empty
$ file onebytefile
onebytefile: very short file (no magic)
os.statの使用
別の方法として、Python の os
モジュールを使って、この情報を確認することもできます。
os.stat()関数は
stat_result` オブジェクトを返します。
このオブジェクトは基本的に、ファイルのプロパティを集めたデータ構造です。
import os
emptyfile = '/mnt/f/code.books/articles/python/emptyfile'
nonemptyfile = '/mnt/f/code.books/articles/python/onebytefile'
result = os.stat(nonemptyfile)
result.st_size # 1
result = os.stat(emptyfile)
result.st_size # 0
os.pathの使用
Python の os.path
モジュールはファイルのパスを非常に簡単に扱えるようにします。
パスの存在を確認したり、パスの種類を区別したりするだけでなく、文字列で指定されたファイルのサイズを取得することもできます。
os.path.getsize()
はパスのようなオブジェクトとして指定されたファイルのサイズを返し、 os.stat()
よりもはるかに使いやすいモジュールです。
import os
emptyfile = '/mnt/f/code.books/articles/python/emptyfile'
nonemptyfile = '/mnt/f/code.books/articles/python/onebytefile'
os.path.getsize(emptyfile) # 0
os.path.getsize(nonemptyfile) # 1
パスリブの使用
Python 3.4 以降を使用している場合、ファイルのサイズを取得するために pathlib
モジュールを使用することができます。
これは基本的に os
モジュールを置き換えるものです。
Path.stat()は
Pathオブジェクトの
stat_resultプロパティを返すが、これは
os.stat()` の戻り値と同じである。
from pathlib import Path
emptyfile = '/mnt/f/code.books/articles/python/emptyfile'
nonemptyfile = '/mnt/f/code.books/articles/python/onebytefile'
print('File stats: ' + Path(emptyfile).stat())
print('File size: ' + Path(emptyfile).stat().st_size + ' byte(s)')
print('File stats: ' + Path(nonemptyfile).stat())
print('File size: ' + Path(nonemptyfile).stat().st_size + ' byte(s)')
この結果は
File stats: os.stat_result(st_mode=33279, st_ino=14355223812249048, st_dev=17, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1600087010, st_mtime=1600087010, st_ctime=1600087010)
File size: 0 byte(s)
File stats: os.stat_result(st_mode=33279, st_ino=5629499534218713, st_dev=17, st_nlink=1, st_uid=0, st_gid=0, st_size=1, st_atime=1600088120, st_mtime=1600088072, st_ctime=1600088072)
File size: 1 byte(s)
ディレクトリが空かどうかを確認する
他のファイルやサブディレクトリを含まないディレクトリを空ディレクトリと呼びます。
ただし、すべてのディレクトリは(空のディレクトリであっても)次の2つのエントリを含んでいます。
- .(ドット)はカレントディレクトリを指し、カレントディレクトリの中にあるものを探したりするときに便利です。
- … (ダブルドット) はカレントディレクトリの親ディレクトリを指し、カレントディレクトリから一歩下がるときに必要です。
ここでは、空のディレクトリを指す変数 emptydirectory
と、空でないディレクトリを指す変数 nonemptydirectory
を定義してみましょう。
emptydirectory = '/mnt/f/code.books/articles/python/markdown'
nonemptydirectory = '/mnt/f/code.books/articles/python/code'
空のディレクトリには、何もアイテムがありません。
$ pwd
/mnt/f/code.books/articles/python/markdown
$ ls -la
total 0
drwxrwxrwx 1 root root 512 Sep 11 11:52 .
drwxrwxrwx 1 root root 512 Sep 10 20:22 ..
空でないディレクトリには、1つのファイルがあります。
$ pwd
/mnt/f/code.books/articles/python/code
$ ls -la
total 0
drwxrwxrwx 1 root root 512 Sep 14 11:02 .
drwxrwxrwx 1 root root 512 Sep 14 18:22 ..
-rwxrwxrwx 1 root root 425 Sep 14 12:27 file_dir.py
os.listdir()の使用法
os.listdir()は、引数として渡されたディレクトリパスで見つかったすべてのアイテムの名前を含むシーケンスを返します。
これは.と
..` のエントリーを含みません。
import os
os.listdir(emptydirectory) # []
os.listdir(nonemptydirectory) # ['file_dir.py']
返されたリストの長さを計算すると、ディレクトリが空かどうかを簡単に判断することができます。
空のディレクトリは常に長さが0になります。
import os
print(len(os.listdir(nonemptydirectory))) # 1
print(len(os.listdir(emptydirectory))) # 0
os.scandir()の使用法
os.listdir()` 関数は、さらなる処理のためにエントリ全体の名前をリストとして必要とする場合に便利です。
しかし、少なくとも1つのエントリがあるかどうかを確認するためには、内部のすべてのファイルのリストは必要ありません。
ディレクトリが巨大な場合、 os.listdir()
関数の実行に長い時間がかかりますが、0
個以上のエントリがあれば疑問は解決します。
この関数は、遅延イテレータブルまたはジェネレータを返します。
ジェネレータは、リストのような通常のイテレータブルのようにループさせることができるイテレータを返します。
しかし、リストやセット、辞書とは異なり、メモリに大量の値を保存せず、代わりに要求に応じて新しい値を返します。
この方法は、~1000ファイル程度のディレクトリであれば、約~200倍高速になります。
ですから、ディレクトリ構造全体をループする代わりに、os.scandir()
を使って、ディレクトリパスの中に少なくとも1つのエントリが見つかったかどうかをチェックすることができます。
import os
emptydirectory = '/mnt/f/code.books/articles/python/markdown'
nonemptydirectory = '/mnt/f/code.books/articles/python/code'
print(next(os.scandir(emptydirectory), None))
print(next(os.scandir(nonemptydirectory), None)) # <direntry 'file_dir.py'=""
これは os.scandir()
が返す遅延イテレータから次の利用可能なアイテムを取得するための組み込み関数です。
emptyydirectoryには利用可能な項目がないため、
Noneを返します。
一方、nonemptydirectoryの場合は
os.DirEntry` オブジェクトを返します。
パスリブの使用
osモジュールの好ましいアプローチとして、
pathlibモジュールがあります。
これはos.listdir()や
os.scandir()` よりもシンプルなだけでなく、とても簡単に使うことができます。
これは、 os.scandir()
と同様に、引数として渡されたディレクトリパスのファイルに対して反復処理を行う遅延イテレートオブジェクトまたはジェネレータオブジェクトを返します。
from pathlib import Path
print(Path(emptydirectory).iterdir()) # <generator 0x7f2cf6f584a0="" at="" object="" path.iterdir=""
next()を使って、次に利用可能なアイテムを取得しようとしています。
デフォルトの戻り値としてNoneを指定すると、コレクション内にアイテムがない場合でも
next()は
StopIteration` 例外を発生させません。
print(next(Path(emptydirectory).iterdir(), None)) # None
print(next(Path(nonemptydirectory).iterdir(), None)) # /mnt/f/code.books/articles/python/code/file_dir.py
Python の組み込み関数のほとんどは、イテラブルを扱うことができます。
any() 関数は、イテラブルに True
と評価できる要素が 1 つでもある場合に、 True
を返します。
from pathlib import Path
print(any(Path(emptydirectory).iterdir()) # False
print(any(nonemptydirectory).iterdir()) # True
結論
このチュートリアルでは、ファイルとディレクトリを区別する方法について説明し、その後、それらが空であるかどうかをチェックしました。
これは os
や pathlib
モジュールとその便利な関数やクラスによって行うことができます。
。