Pythonはどのように特定のタイプのファイルを検索しますか?


前に書く
今日の文章はPythonで特定のタイプのファイルをどのように特定するかを紹介します。文字列でファイル名にマッチして特定のファイルを特定するとともに、ディレクトリツリーの関数を紹介します。今日のこの部分と前の記事で紹介したファイルから属性を取得する操作を通して、面白いことがたくさんできます。
特定ファイルを位置決め
特定のファイルを位置決めして、fnmatchとglobという二つの標準ライブラリを使って、それぞれ見てみます。
1.fnmatch標準ライブラリを使用する
一般的には、特定のタイプのファイルを検索したいです。文字列のプレフィックスマッチングとサフィックスマッチングによって検索できます。具体的な例は以下の通りです。

>>> import os
>>> [txt for txt in os.listdir('.') if txt.endswith('.txt')]
['b.txt', 'a.txt']
ほとんどの場合、このような文字列マッチングの方法でファイルを検索すれば十分です。場合によってはもう少し柔軟な文字列マッチングが必要であれば、fnmatchライブラリを使用することができます。これはファイル名マッチング専用のライブラリです。ワイルドカードを使って文字マッチングを行うことができます。などがあります。
fnmatchというライブラリは簡単です。4つの関数しかありません。fnmatch、fnmatch case、filter、tranlate:
  • fnmatch:ファイル名が特定のパターンに適合しているかどうかを判断する。
  • fnmatichcase:ファイル名が特定のパターンに適合しているかどうかを判断する(大文字と小文字を区別しない)。
  • filter:入力リストに戻り、特定のパターンに合致するファイル名のリストを返す。
  • translate:ワイルドカードモードを正規表現に変換します。
  • 上の4つの最もよく使われているのは、同じ名前の関数fnmatchです。現在のディレクトリの下に4つのファイルがあります。それぞれa.txt、b.txt、c.py、test.py、以下はfnmatch関数を使って、現在のディレクトリの下のこの4つのファイルをマッチングテストします。具体的には下記のコードを見てください。
    
    >>> import os
    >>> import fnmatch
    >>> os.listdir('.')
    ['test.py', 'c.py', 'b.txt', 'a.txt']
    >>> [txt for txt in os.listdir('.') if fnmatch.fnmatch(txt, '*.txt')]
    ['b.txt', 'a.txt']
    >>> [file for file in os.listdir('.') if fnmatch.fnmatch(file, '[a-c]*')]
    ['c.py', 'b.txt', 'a.txt']
    >>> [file for file in os.listdir('.') if fnmatch.fnmatch(file, '[!a-c]*')]
    ['test.py']
    fnmatchcase関数はfnmatch関数とほぼ同じですが、マッチングする時は文字の大きさを無視します。filter関数はfnmatchと似ています。違いはfnmatchが一回に一つのファイル名だけマッチすることです。filterは一回に複数のファイル名にマッチすると判断できます。次にfilterの使い方を見てみます。
    
    >>> import os
    >>> import fnmatch
    >>> file = os.listdir('.')
    >>> file
    ['test.py', 'c.py', 'b.txt', 'a.txt']
    >>> fnmatch.filter(file, '[a-c]*')
    ['c.py', 'b.txt', 'a.txt']
    >>> fnmatch.filter(file, '[!a-c]*')
    ['test.py']
    2.globで位置決めする
    上記で紹介した特定のタイプのファイルリストを取得するには、まずos.listdirを通してすべてのファイルリストを取得し、文字列マッチングまたはfnmatchを使ってファイル名パターンマッチングを行います。Pythonの簡潔で優雅さに慣れました。この多くのステップはどこかおかしいと思いますが、globが分かりました。
    globの役割はos.listdir+fnmatchの組み合わせに相当します。globを使うと、OS.listdirでファイルリストを取得する必要がなく、直接モードマッチングで解決できます。具体的な操作は以下の通りです。
    
    >>> import glob
    >>> glob.glob('*.txt')
    ['b.txt', 'a.txt']
    >>> glob.glob('[a-c]*')
    ['c.py', 'b.txt', 'a.txt']
    >>> glob.glob('[!a-c]*')
    ['test.py']
    見ることができます。Pythonは本当にフレキシブルです。カタログの特定のファイルタイプだけでも3つの方法を紹介しました。普通は文字列でマッチングすれば解決できます。もっと柔軟なものが必要なら、fnmatchとglobを使ってもいいです。
    ディレクトリツリーを巡回
    もう一つのセクションでは、私たちはあるディレクトリのファイルを探して、マッチングによって自分の必要なファイルの種類を特定します。しかし、実際のアプリケーションでは、私たちが出会う可能性が高いのは、あるカタログとそのサブディレクトリのすべてのファイルです。例えば、あるカタログとそのサブディレクトリのすべてのtxtファイルを検索するなど、これらの需要に対して、osモジュールの下の「walk」関数を使うことができます。walk関数は、あるディレクトリとそのサブディレクトリを巡回して、各ディレクトリに対して、walkは3つのグループに戻ります。順番は「現在のディレクトリ」、「現在のディレクトリの下のサブディレクトリ」、「現在のディレクトリの下のファイルリスト」です。
    以下ではOS.walk関数の使い方を示して、小さな練習をして、ディレクトリ/root/rocky 0429とそのサブディレクトリの下のすべてのtxtと画像ファイルを巡回します。
    
    import os
    import fnmatch
    
    search = ['*.txt', '*.jpg', '*.jpeg']
    res = []
    
    for root, dirnames, filenames in os.walk(os.path.expanduser('~/rocky0429')):
      for extension in search:
        for filename in fnmatch.filter(filenames, extension):
          res.append(os.path.join(root,filename))
    
        print(res)
    以上はPythonがどのように特定のタイプのファイルの詳細を調べますか?