Python glob çoklu dosya türleri


142

.Txt, .mdown ve .markdown gibi birden çok dosya türünün listesini almak için python'da glob.glob kullanmanın daha iyi bir yolu var mı? Şu anda böyle bir şey var:

projectFiles1 = glob.glob( os.path.join(projectDir, '*.txt') )
projectFiles2 = glob.glob( os.path.join(projectDir, '*.mdown') )
projectFiles3 = glob.glob( os.path.join(projectDir, '*.markdown') )

Yanıtlar:


156

Belki daha iyi bir yol var, ama nasıl?

import glob
types = ('*.pdf', '*.cpp') # the tuple of file types
files_grabbed = []
for files in types:
    files_grabbed.extend(glob.glob(files))

# files_grabbed is the list of pdf and cpp files

Belki başka bir yol var, bu yüzden başka birinin daha iyi bir cevap bulması için bekleyin.


19
files_grabbed = [glob.glob(e) for e in ['*.pdf', '*.cpp']]
Novitoll

10
Novitoll'un çözümü kısa, ancak sonuçta iç içe listeler oluşturuyor.
robroc

9
bunu her zaman yapabilirsin;)[f for f_ in [glob.glob(e) for e in ('*.jpg', '*.mp4')] for f in f_]
AlexG

1
files_grabbed = [ ' .pdf', '* .cpp']]
florisla

3
Bu, dosya listesinde iki kez dolaşır. İlk yinelemede * .pdf, ikincisinde * .cpp olup olmadığını kontrol eder. Tek bir yinelemede bunu yapmanın bir yolu var mı? Her seferinde kombine durumu kontrol ettiniz mi?
Ridhuvarshan

47
from glob import glob

files = glob('*.gif')
files.extend(glob('*.png'))
files.extend(glob('*.jpg'))

print(files)

Bir yol belirtmeniz gerekiyorsa, eşleşme düzenleri üzerinde döngü yapın ve basitliği sağlamak için birleştirmeyi döngü içinde tutun:

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)

45

glob bir liste döndürür: neden sadece birden çok kez çalıştırıp sonuçları birleştirmeyesiniz?

from glob import glob
project_files = glob('*.txt') + glob('*.mdown') + glob('*.markdown')

3
Bu muhtemelen verilen en okunabilir çözümdür. Ben harf değişikliği olacağını ProjectFilesiçin projectFiles, ama büyük bir çözüm.
Hans Goldman

40

Sonuçları zincirleyin:

import itertools as it, glob

def multiple_file_types(*patterns):
    return it.chain.from_iterable(glob.iglob(pattern) for pattern in patterns)

Sonra:

for filename in multiple_file_types("*.txt", "*.sql", "*.log"):
    # do stuff

13
glob.glob -> glob.iglob böylece yineleyiciler zinciri tamamen tembel değerlendirilir
rodrigob

1
Aynı çözümü buldum ama bilmiyordum chain.from_iterable. Yani bu benzer, ancak daha az okunabilir: it.chain(*(glob.iglob(pattern) for pattern in patterns)).
florisla

17

Sürece uzantı sayısı kadar globbing öneririz birçok cevap, bunun yerine sadece bir kez globbing tercih ediyorum:

from pathlib import Path

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

15

glob ile mümkün değildir. sadece kullanabilirsiniz:
* her şeyi eşleştirir
? herhangi bir tek karakterle eşleşir
[seq], seq'deki herhangi bir karakterle eşleşir
[! seq], seq'de olmayan herhangi bir karakterle eşleşir

kalıpları kontrol etmek için os.listdir ve bir regexp kullanın:

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


1
Bu yaklaşımı seviyorum - glob'un ifadesi yeterince güçlü değilse, daha güçlü bir regex sistemine yükseltin, örneğin kullanarak hacklemeyin, itertoolsçünkü sonraki desen değişiklikleri de hileli olmalıdır (büyük ve küçük harfe izin vermek istediğinizi söyleyin) . Oh, ve yazmak daha temiz olabilir'.*\.(txt|sql)'
metakermit

Os.listdir tercih için herhangi bir neden var mı ( ' ') glob.iglob üzerinde (' . ')?
Mr.WorshipMe

14

Örneğin, birden fazla klasörde *.mp3ve *.flacklasörlerde şunları yapabilirsiniz:

mask = r'music/*/*.[mf][pl][3a]*'
glob.glob(mask)

Fikir daha fazla dosya uzantısına genişletilebilir, ancak kombinasyonların bu klasörlerde olabilecek diğer dosya uzantılarıyla eşleşip eşleşmediğini kontrol etmeniz gerekir. Bu yüzden dikkatli olun .

İsteğe bağlı uzantılar listesini otomatik olarak tek bir glob deseninde birleştirmek için aşağıdakileri yapabilirsiniz:

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

6

Tek katlı, sadece cehennem için ..

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]

çıktı:

['C:\\multi_pattern_glob_one_liner\\dummy_txt.txt', 'C:\\multi_pattern_glob_one_liner\\dummy_bat.bat']

4

Yardım için buraya geldikten sonra kendi çözümümü yaptım ve paylaşmak istedim. Kullanıcı2363986'nın cevabına dayanıyor, ancak bence bu daha ölçeklenebilir. Yani, 1000 uzantınız varsa, kod yine de biraz zarif görünecektir.

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

Benim için çalışmıyor. Ben kullanımdirectoryPath = "/Users/bla/bla/images_dir*."
NeStack

Bunu sizin için hata ayıklamak için daha fazla bilgiye ihtiyacım var ... İstisna mı alıyorsunuz? Ayrıca, Windows kullanıyorsanız, bu yol işe yarayacak gibi görünmüyor (eksik sürücü harfi).
Hans Goldman

4
files = glob.glob('*.txt')
files.extend(glob.glob('*.dat'))

4
İyi yanıtlar ayrıca kodun bazı açıklamalarını ve belki de kodun arkasındaki akıl yürütmenizin bir kısmını sağlar.
SunSparc

4

Python'un varsayılan glob'u Bash'ın glob'ından sonra gerçekten takip etmese de, bunu diğer kütüphanelerle yapabilirsiniz. Wcmatch'ın küresinde parantezleri etkinleştirebiliriz .

>>> from wcmatch import glob
>>> glob.glob('*.{md,ini}', flags=glob.BRACE)
['LICENSE.md', 'README.md', 'tox.ini']

Tercihiniz buysa genişletilmiş glob kalıpları bile kullanabilirsiniz :

from wcmatch import glob
>>> glob.glob('*.@(md|ini)', flags=glob.EXTGLOB)
['LICENSE.md', 'README.md', 'tox.ini']

Bu recursivebayrağı almaz
Shamoon

@Shamoon Hayır, glob.GLOBSTARbayrağı alıyor
facelessuser

3

Ben yayımlandı formik Apache Ant'ın benzer şekilde içeren uygular çoklu dosya gurubu ve Globs .

Arama uygulanabilir:

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

Tam Karınca küresi uygulandığından, her desene farklı dizinler ekleyebilirsiniz, böylece yalnızca bir alt dizindeki bu .txt dosyalarını ve başka birindeki .markdown'u seçebilirsiniz, örneğin:

patterns = [ "/unformatted/**/*.txt", "/formatted/**/*.mdown" ]

Umarım bu yardımcı olur.


3

_globBirden fazla dosya uzantısı için aşağıdaki işlev globları.

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

3

Bu bir Python 3.4+ pathlibçözümüdür:

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

Ayrıca ile başlayan tüm dosya adlarını yok sayar ~.


3

İşte Pat'ın cevabının (ayrıca belirli bir proje dizininde zorlamak istediğinizi içeren) tek satırlık bir liste anlama varyantı:

import os, glob
exts = ['*.txt', '*.mdown', '*.markdown']
files = [f for ext in exts for f in glob.glob(os.path.join(project_dir, ext))]

Uzantıların ( for ext in exts) üzerine döngü yaparsınız ve her uzantı için glob kalıbıyla ( for f in glob.glob(os.path.join(project_dir, ext)) eşleşen her dosyayı alırsınız .

Bu çözüm kısadır ve gereksiz for-döngüler, iç içe liste kavrayışları veya kodun dağınıklığı için işlevler içermez. Sadece saf, etkileyici, pitonik Zen .

Bu çözüm, extskodunuzu güncellemek zorunda kalmadan değiştirebileceğiniz özel bir listeye sahip olmanızı sağlar. (Bu her zaman iyi bir uygulamadır!)

Liste anlama, Laurent'in çözümünde kullanılanla aynıdır (buna oy verdim). Ancak, tek bir satırı ayrı bir işleve ayırmanın genellikle gereksiz olduğunu savunuyorum, bu yüzden bunu alternatif bir çözüm olarak sağlıyorum.

Bonus:

Yalnızca tek bir dizinde değil, tüm alt dizinlerde de arama yapmanız gerekiyorsa recursive=True, çok dizinli glob sembolünü ** 1 geçebilir ve kullanabilirsiniz :

files = [f for ext in exts 
         for f in glob.glob(os.path.join(project_dir, '**', ext), recursive=True)]

Bu, glob.glob('<project_dir>/**/*.txt', recursive=True)her uzantı için çağrılacaktır.

1 Teknik olarak, **glob sembolü , eğik çizgi / (tekil *glob sembolünün aksine) dahil olmak üzere bir veya daha fazla karakterle eşleşir . Pratikte, sadece **eğik çizgilerle (yol ayırıcılar) çevrelediğiniz sürece , sıfır veya daha fazla dizinle eşleştiğini hatırlamanız gerekir .


2

Hayır glob, ancak liste kavramasını kullanmanın başka bir yolu:

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

1

Mevcut olanın uzantısını ihtiyacınız olanlarla karşılaştırarak manuel bir liste yapmaya çalışabilirsiniz.

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

Birden globçok dosya türünde, glob()işlevi bir döngüde birkaç kez çağırmanız gerekir . Bu işlev bir liste döndürdüğünden, listeleri birleştirmeniz gerekir.

Örneğin, bu işlev işi yapar:

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

Basit kullanım:

project_dir = "path/to/project/dir"
for path in sorted(glob_filetypes(project_dir, '*.txt', '*.mdown', '*.markdown')):
    print(path)

glob.iglob()Bir yineleyiciye sahip olmak için de kullanabilirsiniz :

Hepsini aynı anda saklamadan glob () ile aynı değerleri veren bir yineleyici döndürün.

def iglob_filetypes(root_dir, *patterns):
    return (path
            for pattern in patterns
            for path in glob.iglob(os.path.join(root_dir, pattern)))

1

Bir uzantı listesi kullanın ve

from os.path import join
from glob import glob

files = []
extensions = ['*.gif', '*.png', '*.jpg']
for ext in extensions:
   files.extend(glob(join("path/to/dir", ext)))

print(files)

0

Filtre kullanabilirsiniz:

import os
import glob

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

0

Ayrıca şöyle kullanabilirsiniz reduce():

import glob
file_types = ['*.txt', '*.mdown', '*.markdown']
project_files = reduce(lambda list1, list2: list1 + list2, (glob.glob(t) for t in file_types))

bu, glob.glob()her desen için bir liste oluşturur ve bunları tek bir listeye indirir.


0

Bir glob, birçok uzantı ... ancak kusurlu bir çözüm (diğer dosyalarla eşleşebilir).

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

Ben de aynı sorunu yaşadım ve işte bu

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

Yine başka bir çözüm (kullanmak globçoklu eşleme kullanarak yolları almak patternsve kullanarak tek liste halinde bütün yolları birleştirmek reduceve add):

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

0

Kullanıyorsanız şunu pathlibdeneyin:

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

Ampirik testlerden elde ettiğim sonuçlara glob.globgöre, dosyaları uzantılarına göre filtrelemenin daha iyi bir yolu olmadığı ortaya çıktı . Sebeplerden bazıları:

  • Globbing " dil " çoklu uzantının mükemmel bir şekilde belirlenmesine izin vermez.
  • Önceki nokta, dosya uzantılarına bağlı olarak yanlış sonuçlar elde edilmesiyle sonuçlanır.
  • Globbing yönteminin ampirik olarak diğer birçok yöntemden daha yavaş olduğu kanıtlanmıştır.
  • Diğer dosya sistemleri nesnelerinin bile " uzantıları ", klasörleri olabilir garip olsa bile .

4Dosyaları uzantılara göre filtrelemek için aşağıdaki farklı yöntemleri test ettim (zamanında doğruluk ve verimlilik için) ve bunları bir yere koydum 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

Yukarıdaki kodu dizüstü bilgisayarımda çalıştırarak aşağıdaki otomatik açıklayıcı sonuçları elde ettim.

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.

Dosyaları uzantılara göre filtrelemenin en hızlı yolu, en çirkin bile olsa. Yani, iç içe fordöngüler ve yöntem stringkullanarak karşılaştırma endswith().

Dahası, gördüğünüz gibi, E:\x\y\z\**/*[py][pyc]sadece 2uzatma ile ( pyve pyc) bile globbing algoritmaları (desenli ) de yanlış sonuçlar verir.


0
import glob
import pandas as pd

df1 = pd.DataFrame(columns=['A'])
for i in glob.glob('C:\dir\path\*.txt'):
    df1 = df1.append({'A': i}, ignore_index=True)
for i in glob.glob('C:\dir\path\*.mdown'):
    df1 = df1.append({'A': i}, ignore_index=True)
for i in glob.glob('C:\dir\path\*.markdown):
    df1 = df1.append({'A': i}, ignore_index=True)

Merhaba Sway Wu, hoş geldiniz. Lütfen bir açıklama eklemeyi düşünün.
Tiago Martins Peres

-1

Bu çalışmalı:

import glob
extensions = ('*.txt', '*.mdown', '*.markdown')
for i in extensions:
    for files in glob.glob(i):
        print (files)

-1

Örneğin:

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

Bir işlev:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.