web-dev-qa-db-ja.com

Python glob複数のファイルタイプ

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') )
110
Raptrex

もっと良い方法があるかもしれませんが、どうですか:

>>> 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

おそらく別の方法があるので、他の誰かがより良い答えを思い付くのを待ってください。

122
user225312
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)
39
user2363986

結果の連鎖:

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
34
tzot

globはリストを返します。なぜそれを複数回実行して結果を連結しないのですか?

from glob import glob
ProjectFiles = glob('*.txt') + glob('*.mdown') + glob('*markdown')
26
patrick-mooney

globでは不可能です。次のもののみ使用できます。
*はすべてに一致します
?任意の1文字と一致します
[seq]は、seqの任意の文字に一致します
[!seq]は、seqにない任意の文字に一致します

os.listdirと正規表現を使用してパターンをチェックします。

for x in os.listdir('.'):
  if re.match('.*\.txt|.*\.sql', x):
    print x
15
Christian

たとえば、複数のフォルダの*.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]*
10
feqwix

ワンライナー、まさにそれのために..

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']
5
Gil-Mor

助けを求めてここに来た後、私は自分で解決策を作り、それを共有したいと考えました。 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
4
Hans Goldman

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個以上のディレクトリと一致することに注意してください。

3
scholer
files = glob.glob('*.txt')
files.extend(glob.glob('*.dat'))
3
Derek White

これは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("~"))

また、~で始まるすべてのファイル名を無視します。

3
Winand

globではありませんが、リスト内包表記を使用する別の方法を次に示します。

extensions = 'txt mdown markdown'.split()
projectFiles = [f for f in os.listdir(projectDir) 
                  if os.path.splitext(f)[1][1:] in extensions]
2
joemaller

拡張機能の数と同じくらい多くのグロビングを示唆する多くの回答があるので、代わりに一度だけグロビングすることをお勧めします。

from pathlib import Path

files = {p.resolve() for p in Path(path).glob("**/*") if p.suffix in [".c", ".cc", ".cpp", ".hxx", ".h"]}
2
BPL

次の関数_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")
2
Tim Fuller

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" ]

これがお役に立てば幸いです。

2
Andrew Alcock

複数のファイルタイプを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)))
1
Laurent LAPORTE

経験的なテストから得た結果から、glob.globは拡張子でファイルを除外するより良い方法ではないことがわかりました。理由のいくつかは次のとおりです。

  • グロビング「language」では、複数の拡張子を完全に指定することはできません。
  • 前者の場合、ファイル拡張子に応じて誤った結果が得られます。
  • グロビング法は、他のほとんどの方法よりも遅いことが経験的に証明されています。
  • 他のファイルシステムオブジェクトでさえ「extensions」を持つことができます。

次の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)のみが指定されていても、誤った結果を返します。

0
Giova

既存の拡張子と必要な拡張子を比較する手動リストを作成してみてください。

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)
0
thegauraw

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)
0
colllin

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()からリストを作成し、それらを単一のリストに減らします。

0
cyht

拡張機能のリストを使用して繰り返し処理する

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)
0
Projesh Bhoumik
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

0
unpangloss

フィルタを使用できます:

import os
import glob

projectFiles = filter(
    lambda x: os.path.splitext(x)[1] in [".txt", ".mdown", ".markdown"]
    glob.glob(os.path.join(projectDir, "*"))
)
0
LK__

さらに別の解決策(globを使用して複数の一致patternsを使用してパスを取得し、reduceおよびaddを使用してすべてのパスを単一のリストに結合します):

import functools, glob, operator
paths = functools.reduce(operator.add, [glob.glob(pattern) for pattern in [
    "path1/*.ext1",
    "path2/*.ext2"]])
0
Petr Vepřek

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))
0
qik

私は同じ問題を抱えていて、これが私が思いついたものです

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))
0
Justin

例えば:

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
0
Jayhello