Python ファイルやディレクトリが空かどうかをチェックする

Pythonには、このタスクを支援するための組み込みのライブラリオブジェクトと関数のセットがあります。

このチュートリアルでは、Pythonでファイルやディレクトリが空かどうかをチェックする方法を学びます。

ファイルとディレクトリの見分け方

パスが空かどうかを調べたいとき、それがファイルなのかディレクトリなのかを知っておくと、使用するアプローチに影響するからです。

例えば、ローカルのディレクトリとファイルを識別する2つのプレースホルダ変数 dirpathfilepath があるとしましょう。

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 モジュールが導入されました。

pathlibosos.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 バイトの空のファイルを指す変数 emptyfilenonemptyfile を定義しておこう。

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


結論

このチュートリアルでは、ファイルとディレクトリを区別する方法について説明し、その後、それらが空であるかどうかをチェックしました。

これは ospathlib モジュールとその便利な関数やクラスによって行うことができます。

タイトルとURLをコピーしました