フォルダー内の一連のサブフォルダーを開き、いくつかのテキストファイルを見つけて、テキストファイルのいくつかの行を印刷します。私はこれを使用しています:
configfiles = glob.glob('C:/Users/sam/Desktop/file1/*.txt')
ただし、これはサブフォルダーにもアクセスできません。同じコマンドを使用してサブフォルダーにアクセスする方法を知っている人はいますか?
Python 3.5以降では、新しい再帰**/
機能を使用します。
configfiles = glob.glob('C:/Users/sam/Desktop/file1/**/*.txt', recursive=True)
recursive
が設定されている場合、**
の後にパス区切り文字が続くと、0個以上のサブディレクトリに一致します。
以前のPythonバージョンでは、glob.glob()
はサブディレクトリ内のファイルを再帰的にリストできません。
その場合、代わりに os.walk()
を fnmatch.filter()
と組み合わせて使用します:
import os
import fnmatch
path = 'C:/Users/sam/Desktop/file1'
configfiles = [os.path.join(dirpath, f)
for dirpath, dirnames, files in os.walk(path)
for f in fnmatch.filter(files, '*.txt')]
これにより、ディレクトリが再帰的に調べられ、一致する.txt
ファイルへのすべての絶対パス名が返されます。このspecificの場合、fnmatch.filter()
が過剰である可能性があるため、.endswith()
テストを使用することもできます。
import os
path = 'C:/Users/sam/Desktop/file1'
configfiles = [os.path.join(dirpath, f)
for dirpath, dirnames, files in os.walk(path)
for f in files if f.endswith('.txt')]
直下のサブディレクトリでファイルを見つけるには:
configfiles = glob.glob(r'C:\Users\sam\Desktop\*\*.txt')
すべてのサブディレクトリをトラバースする再帰バージョンの場合、**
を使用してrecursive=True
を渡すことができます Python 3.5以降 :
configfiles = glob.glob(r'C:\Users\sam\Desktop\**\*.txt', recursive=True)
両方の関数呼び出しはリストを返します。 glob.iglob()
を使用して、パスを1つずつ返すことができます。または pathlib
を使用 :
from pathlib import Path
path = Path(r'C:\Users\sam\Desktop')
txt_files_only_subdirs = path.glob('*/*.txt')
txt_files_all_recursively = path.rglob('*.txt') # including the current dir
どちらのメソッドも反復子を返します(パスを1つずつ取得できます)。
glob2 パッケージはワイルドカードをサポートし、かなり高速です
code = '''
import glob2
glob2.glob("files/*/**")
'''
timeit.timeit(code, number=1)
私のラップトップでは、一致するのに約2秒かかります > 60,000ファイルパス 。
Python 2.6で Formic を使用できます
import formic
fileset = formic.FileSet(include="**/*.txt", directory="C:/Users/sam/Desktop/")
開示-私はこのパッケージの著者です。
以下は、glob.glob
を使用せずにglob2
のような機能を有効にする適応バージョンです。
def find_files(directory, pattern='*'):
if not os.path.exists(directory):
raise ValueError("Directory not found {}".format(directory))
matches = []
for root, dirnames, filenames in os.walk(directory):
for filename in filenames:
full_path = os.path.join(root, filename)
if fnmatch.filter([full_path], pattern):
matches.append(os.path.join(root, filename))
return matches
したがって、次のディレクトリ構造がある場合
tests/files
├── a0
│ ├── a0.txt
│ ├── a0.yaml
│ └── b0
│ ├── b0.yaml
│ └── b00.yaml
└── a1
このようなことができます
files = utils.find_files('tests/files','**/b0/b*.yaml')
> ['tests/files/a0/b0/b0.yaml', 'tests/files/a0/b0/b00.yaml']
ほとんどのfnmatch
パターンは、ファイル名のみではなく、ファイル名全体で一致します。
Python 3.4+を実行している場合は、 pathlib
モジュールを使用できます。 Path.glob()
メソッドは**
パターンをサポートします。これは、「このディレクトリとすべてのサブディレクトリを再帰的に」意味します。一致するすべてのファイルに対して Path
オブジェクトを生成するジェネレーターを返します。
from pathlib import Path
configfiles = Path("C:/Users/sam/Desktop/file1/").glob("**/*.txt")
configfiles = glob.glob('C:/Users/sam/Desktop/**/*.txt")
すべての場合に機能するわけではなく、代わりにglob2を使用します
configfiles = glob2.glob('C:/Users/sam/Desktop/**/*.txt")
このトピックには多くの混乱があります。それを明確にすることができるかどうかを見てみましょう(Python 3.7):
glob.glob('*.txt') :
は、現在のディレクトリの「.txt」で終わるすべてのファイルに一致しますglob.glob('*/*.txt') :
1と同じglob.glob('**/*.txt') :
は、イミディエイトサブディレクトリのみで '.txt'で終わるすべてのファイルに一致しますが、現在のディレクトリには一致しませんglob.glob('*.txt',recursive=True) :
1と同じglob.glob('*/*.txt',recursive=True) :
3と同じglob.glob('**/*.txt',recursive=True):
は、現在のディレクトリとすべてのサブディレクトリにある「.txt」で終わるすべてのファイルに一致しますそのため、常にrecursive=True.
を指定するのが最善です
Glob2パッケージをインストールできる場合...
import glob2
filenames = glob2.glob("C:\\top_directory\\**\\*.ext") # Where ext is a specific file extension
folders = glob2.glob("C:\\top_directory\\**\\")
すべてのファイル名とフォルダー:
all_ff = glob2.glob("C:\\top_directory\\**\\**")
Martijnが指摘したように、globはPython 3.5で導入された**
operatorを介してのみこれを行うことができます。 OPはglobモジュールを明示的に要求したため、以下は同様に動作する遅延評価イテレータを返します
import os, glob, itertools
configfiles = itertools.chain.from_iterable(glob.iglob(os.path.join(root,'*.txt'))
for root, dirs, files in os.walk('C:/Users/sam/Desktop/file1/'))
ただし、このアプローチではconfigfiles
を1回しか反復できないことに注意してください。複数の操作で使用できる設定ファイルの実際のリストが必要な場合は、list(configfiles)
を使用して明示的に作成する必要があります。