pythonでglob.globを使用して、.txt、.mdown、.markdownなどの複数のファイルタイプのリストを取得するより良い方法はありますか?今、私はこのようなものを持っています:
projectFiles1 = glob.glob( os.path.join(projectDir, '*.txt') )
projectFiles2 = glob.glob( os.path.join(projectDir, '*.mdown') )
projectFiles3 = glob.glob( os.path.join(projectDir, '*.markdown') )
もっと良い方法があるかもしれませんが、どうですか:
>>> import glob
>>> types = ('*.pdf', '*.cpp') # the Tuple of file types
>>> files_grabbed = []
>>> for files in types:
... files_grabbed.extend(glob.glob(files))
...
>>> files_grabbed # the list of pdf and cpp files
おそらく別の方法があるので、他の誰かがより良い答えを思い付くのを待ってください。
from glob import glob
files = glob('*.gif')
files.extend(glob('*.png'))
files.extend(glob('*.jpg'))
print(files)
パスを指定する必要がある場合は、単純化のために、一致パターンをループしてループ内に結合を保持します。
from os.path import join
from glob import glob
files = []
for ext in ('*.gif', '*.png', '*.jpg'):
files.extend(glob(join("path/to/dir", ext)))
print(files)
結果の連鎖:
import itertools as it, glob
def multiple_file_types(*patterns):
return it.chain.from_iterable(glob.iglob(pattern) for pattern in patterns)
次に:
for filename in multiple_file_types("*.txt", "*.sql", "*.log"):
# do stuff
glob
はリストを返します。なぜそれを複数回実行して結果を連結しないのですか?
from glob import glob
ProjectFiles = glob('*.txt') + glob('*.mdown') + glob('*markdown')
globでは不可能です。次のもののみ使用できます。
*はすべてに一致します
?任意の1文字と一致します
[seq]は、seqの任意の文字に一致します
[!seq]は、seqにない任意の文字に一致します
os.listdirと正規表現を使用してパターンをチェックします。
for x in os.listdir('.'):
if re.match('.*\.txt|.*\.sql', x):
print x
たとえば、複数のフォルダの*.mp3
および*.flac
の場合、次のことができます。
mask = r'music/*/*.[mf][pl][3a]*'
glob.glob(mask)
このアイデアは、より多くのファイル拡張子に拡張できます。butあなたが持っている他の不要なファイル拡張子と組み合わせが一致しないことを確認する必要がありますそれらのフォルダ。したがって、注意これで。
拡張機能の任意のリストを単一のglobパターンに自動的に結合するには、次の操作を実行できます。
mask_base = r'music/*/*.'
exts = ['mp3', 'flac', 'wma']
chars = ''.join('[{}]'.format(''.join(set(c))) for c in Zip(*exts))
mask = mask_base + chars + ('*' if len(set(len(e) for e in exts)) > 1 else '')
print(mask) # music/*/*.[fmw][plm][3a]*
ワンライナー、まさにそれのために..
folder = "C:\\multi_pattern_glob_one_liner"
files = [item for sublist in [glob.glob(folder + ext) for ext in ["/*.txt", "/*.bat"]] for item in sublist]
出力:
['C:\\multi_pattern_glob_one_liner\\dummy_txt.txt', 'C:\\multi_pattern_glob_one_liner\\dummy_bat.bat']
助けを求めてここに来た後、私は自分で解決策を作り、それを共有したいと考えました。 user2363986の回答に基づいていますが、これはよりスケーラブルだと思います。つまり、拡張機能が1000個ある場合でも、コードはややエレガントに見えます。
from glob import glob
directoryPath = "C:\\temp\\*."
fileExtensions = [ "jpg", "jpeg", "png", "bmp", "gif" ]
listOfFiles = []
for extension in fileExtensions:
listOfFiles.extend( glob( directoryPath + extension ))
for file in listOfFiles:
print(file) # Or do other stuff
Patの回答の1行のリスト理解版(これには、特定のプロジェクトディレクトリにグロブすることも含まれています):
import os, glob
exts = ['*.txt', '*.mdown', '*.markdown']
files = [f for ext in exts for f in glob.glob(os.path.join(project_dir, ext))]
拡張機能(for ext in exts
)をループし、拡張機能ごとに、globパターンに一致する各ファイル(for f in glob.glob(os.path.join(project_dir, ext)
)を取得します。
この解決策はshortであり、不要なforループ、ネストされたリスト内包表記、またはコードを乱雑にする関数はありません。純粋で表現力豊かなPythonic Zen。
このソリューションを使用すると、コードを更新せずに変更できるexts
のカスタムリストを作成できます。 (これは常に良い習慣です!)
リスト内包表記は、Laurentのソリューションで使用したものと同じです(私は投票しました)。しかし、通常、単一の行を別の関数に分解する必要はないと主張します。これが代替ソリューションとしてこれを提供している理由です。
ボーナス:
単一のディレクトリだけでなく、すべてのサブディレクトリも検索する必要がある場合は、recursive=True
を渡し、マルチディレクトリglobシンボル**
を使用できます。 1:
files = [f for ext in exts
for f in glob.glob(os.path.join(project_dir, '**', ext), recursive=True)]
これにより、各拡張機能に対してglob.glob('<project_dir>/**/*.txt', recursive=True)
などが呼び出されます。
1 技術的には、**
globシンボルは、1つ以上の文字と単純に一致しますスラッシュを含む/
(単数の*
globシンボルとは異なります)。実際には、**
をスラッシュ(パス区切り記号)で囲む限り、0個以上のディレクトリと一致することに注意してください。
files = glob.glob('*.txt')
files.extend(glob.glob('*.dat'))
これはPython 3.4+ pathlib
ソリューションです。
exts = ".pdf", ".doc", ".xls", ".csv", ".ppt"
filelist = (str(i) for i in map(pathlib.Path, os.listdir(src)) if i.suffix.lower() in exts and not i.stem.startswith("~"))
また、~
で始まるすべてのファイル名を無視します。
glob
ではありませんが、リスト内包表記を使用する別の方法を次に示します。
extensions = 'txt mdown markdown'.split()
projectFiles = [f for f in os.listdir(projectDir)
if os.path.splitext(f)[1][1:] in extensions]
拡張機能の数と同じくらい多くのグロビングを示唆する多くの回答があるので、代わりに一度だけグロビングすることをお勧めします。
from pathlib import Path
files = {p.resolve() for p in Path(path).glob("**/*") if p.suffix in [".c", ".cc", ".cpp", ".hxx", ".h"]}
次の関数_glob
は、複数のファイル拡張子のグロブです。
import glob
import os
def _glob(path, *exts):
"""Glob for multiple file extensions
Parameters
----------
path : str
A file name without extension, or directory name
exts : Tuple
File extensions to glob for
Returns
-------
files : list
list of files matching extensions in exts in path
"""
path = os.path.join(path, "*") if os.path.isdir(path) else path + "*"
return [f for files in [glob.glob(path + ext) for ext in exts] for f in files]
files = _glob(projectDir, ".txt", ".mdown", ".markdown")
Apache Antの FileSet and Globs と同様の方法で複数のインクルードを実装する Formic をリリースしました。
検索を実装できます:
import formic
patterns = ["*.txt", "*.markdown", "*.mdown"]
fileset = formic.FileSet(directory=projectDir, include=patterns)
for file_name in fileset.qualified_files():
# Do something with file_name
完全なAntグロブが実装されているため、パターンごとに異なるディレクトリを含めることができるため、1つのサブディレクトリでは.txtファイルのみを選択し、別のサブディレクトリでは.markdownを選択できます。
patterns = [ "/unformatted/**/*.txt", "/formatted/**/*.mdown" ]
これがお役に立てば幸いです。
複数のファイルタイプをglob
するには、ループで glob()
関数を数回呼び出す必要があります。この関数はリストを返すため、リストを連結する必要があります。
たとえば、この関数は次のことを行います。
import glob
import os
def glob_filetypes(root_dir, *patterns):
return [path
for pattern in patterns
for path in glob.glob(os.path.join(root_dir, pattern))]
簡単な使用法:
project_dir = "path/to/project/dir"
for path in sorted(glob_filetypes(project_dir, '*.txt', '*.mdown', '*.markdown')):
print(path)
glob.iglob()
を使用してイテレータを作成することもできます。
実際にすべてを同時に保存せずに、glob()と同じ値を返すイテレータを返します。
def iglob_filetypes(root_dir, *patterns):
return (path
for pattern in patterns
for path in glob.iglob(os.path.join(root_dir, pattern)))
経験的なテストから得た結果から、glob.glob
は拡張子でファイルを除外するより良い方法ではないことがわかりました。理由のいくつかは次のとおりです。
次の4
さまざまな方法でファイルを拡張子でフィルターし、list
に配置することをテストしました(時間の正確さと効率のため)。
from glob import glob, iglob
from re import compile, findall
from os import walk
def glob_with_storage(args):
elements = ''.join([f'[{i}]' for i in args.extensions])
globs = f'{args.target}/**/*{elements}'
results = glob(globs, recursive=True)
return results
def glob_with_iteration(args):
elements = ''.join([f'[{i}]' for i in args.extensions])
globs = f'{args.target}/**/*{elements}'
results = [i for i in iglob(globs, recursive=True)]
return results
def walk_with_suffixes(args):
results = []
for r, d, f in walk(args.target):
for ff in f:
for e in args.extensions:
if ff.endswith(e):
results.append(path_join(r,ff))
break
return results
def walk_with_regs(args):
reg = compile('|'.join([f'{i}$' for i in args.extensions]))
results = []
for r, d, f in walk(args.target):
for ff in f:
if len(findall(reg,ff)):
results.append(path_join(r, ff))
return results
私のラップトップで上記のコードを実行すると、次の自動説明的な結果が得られました。
Elapsed time for '7 times glob_with_storage()': 0.365023 seconds.
mean : 0.05214614
median : 0.051861
stdev : 0.001492152
min : 0.050864
max : 0.054853
Elapsed time for '7 times glob_with_iteration()': 0.360037 seconds.
mean : 0.05143386
median : 0.050864
stdev : 0.0007847381
min : 0.050864
max : 0.052859
Elapsed time for '7 times walk_with_suffixes()': 0.26529 seconds.
mean : 0.03789857
median : 0.037899
stdev : 0.0005759071
min : 0.036901
max : 0.038896
Elapsed time for '7 times walk_with_regs()': 0.290223 seconds.
mean : 0.04146043
median : 0.040891
stdev : 0.0007846776
min : 0.04089
max : 0.042885
Results sizes:
0 2451
1 2451
2 2446
3 2446
Differences between glob() and walk():
0 E:\x\y\z\venv\lib\python3.7\site-packages\Cython\Includes\numpy
1 E:\x\y\z\venv\lib\python3.7\site-packages\Cython\Utility\CppSupport.cpp
2 E:\x\y\z\venv\lib\python3.7\site-packages\future\moves\xmlrpc
3 E:\x\y\z\venv\lib\python3.7\site-packages\Cython\Includes\libcpp
4 E:\x\y\z\venv\lib\python3.7\site-packages\future\backports\xmlrpc
Elapsed time for 'main': 1.317424 seconds.
拡張子でファイルを除外する最速の方法は、たまたま最もuいものです。つまり、ネストされたfor
ループと、endswith()
メソッドを使用したstring
比較です。
さらに、ご覧のとおり、グロビングアルゴリズム(パターンE:\x\y\z\**/*[py][pyc]
)は、2
拡張子(py
およびpyc
)のみが指定されていても、誤った結果を返します。
既存の拡張子と必要な拡張子を比較する手動リストを作成してみてください。
ext_list = ['gif','jpg','jpeg','png'];
file_list = []
for file in glob.glob('*.*'):
if file.rsplit('.',1)[1] in ext_list :
file_list.append(file)
1つのグロブ、多くの拡張子...が不完全なソリューション(他のファイルと一致する可能性があります)。
filetypes = ['tif', 'jpg']
filetypes = Zip(*[list(ft) for ft in filetypes])
filetypes = ["".join(ch) for ch in filetypes]
filetypes = ["[%s]" % ch for ch in filetypes]
filetypes = "".join(filetypes) + "*"
print(filetypes)
# => [tj][ip][fg]*
glob.glob("/path/to/*.%s" % filetypes)
reduce()
を次のように使用することもできます。
import glob
file_types = ['*.txt', '*.mdown', '*.markdown']
project_files = reduce(lambda list1, list2: list1 + list2, (glob.glob(t) for t in file_types))
これは、パターンごとにglob.glob()
からリストを作成し、それらを単一のリストに減らします。
拡張機能のリストを使用して繰り返し処理する
from os.path import join
from glob import glob
files = ['*.gif', '*.png', '*.jpg']
for ext in files:
files.extend(glob(join("path/to/dir", ext)))
print(files)
import os
import glob
import operator
from functools import reduce
types = ('*.jpg', '*.png', '*.jpeg')
lazy_paths = (glob.glob(os.path.join('my_path', t)) for t in types)
paths = reduce(operator.add, lazy_paths, [])
https://docs.python.org/3.5/library/functools.html#functools.reducehttps://docs.python.org/3.5/library/operator.html# operator.add
フィルタを使用できます:
import os
import glob
projectFiles = filter(
lambda x: os.path.splitext(x)[1] in [".txt", ".mdown", ".markdown"]
glob.glob(os.path.join(projectDir, "*"))
)
さらに別の解決策(glob
を使用して複数の一致patterns
を使用してパスを取得し、reduce
およびadd
を使用してすべてのパスを単一のリストに結合します):
import functools, glob, operator
paths = functools.reduce(operator.add, [glob.glob(pattern) for pattern in [
"path1/*.ext1",
"path2/*.ext2"]])
pathlib
を使用する場合は、これを試してください。
import pathlib
extensions = ['.py', '.txt']
root_dir = './test/'
files = filter(lambda p: p.suffix in extensions, pathlib.Path(root_dir).glob('**/*'))
print(list(files))
私は同じ問題を抱えていて、これが私が思いついたものです
import os, sys, re
#without glob
src_dir = '/mnt/mypics/'
src_pics = []
ext = re.compile('.*\.(|{}|)$'.format('|'.join(['png', 'jpeg', 'jpg']).encode('utf-8')))
for root, dirnames, filenames in os.walk(src_dir):
for filename in filter(lambda name:ext.search(name),filenames):
src_pics.append(os.path.join(root, filename))
例えば:
import glob
lst_img = []
base_dir = '/home/xy/img/'
# get all the jpg file in base_dir
lst_img += glob.glob(base_dir + '*.jpg')
print lst_img
# ['/home/xy/img/2.jpg', '/home/xy/img/1.jpg']
# append all the png file in base_dir to lst_img
lst_img += glob.glob(base_dir + '*.png')
print lst_img
# ['/home/xy/img/2.jpg', '/home/xy/img/1.jpg', '/home/xy/img/3.png']
機能:
import glob
def get_files(base_dir='/home/xy/img/', lst_extension=['*.jpg', '*.png']):
"""
:param base_dir:base directory
:param lst_extension:lst_extension: list like ['*.jpg', '*.png', ...]
:return:file lists like ['/home/xy/img/2.jpg','/home/xy/img/3.png']
"""
lst_files = []
for ext in lst_extension:
lst_files += glob.glob(base_dir+ext)
return lst_files