Beberapa tipe file Python glob


150

Apakah ada cara yang lebih baik untuk menggunakan glob.glob dengan python untuk mendapatkan daftar beberapa jenis file seperti .txt, .mdown, dan .markdown? Sekarang saya memiliki sesuatu seperti ini:

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


Mengapa tidak main_file = projectFiles1 + projectFiles2 + projectFiles3? yang juga akan mengarah ke daftar utama dengan semua jenis dengan penggabungan
Cool Cloud

Jawaban:


166

Mungkin ada cara yang lebih baik, tapi bagaimana dengan:

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

Mungkin ada cara lain, jadi tunggu kalau-kalau ada orang lain yang memberikan jawaban yang lebih baik.


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

13
Solusi Novitoll singkat, tetapi akhirnya membuat daftar bersarang.
robroc

10
Anda selalu bisa melakukan ini;)[f for f_ in [glob.glob(e) for e in ('*.jpg', '*.mp4')] for f in f_]
AlexG

1
files_grabbed = [ glob.glob (e) untuk e dalam [' .pdf', '* .cpp']]
florisla

3
Ini mengulang dua kali melalui daftar file. Pada iterasi pertama ia memeriksa * .pdf dan yang kedua memeriksa * .cpp. Apakah ada cara untuk menyelesaikannya dalam satu iterasi? Periksa kondisi gabungan setiap kali?
Ridhuvarshan

52
from glob import glob

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

print(files)

Jika Anda perlu menentukan jalur, putar ulang pola kecocokan dan pertahankan gabungan di dalam perulangan untuk kesederhanaan:

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)

50

glob mengembalikan daftar: mengapa tidak menjalankannya beberapa kali dan menggabungkan hasilnya?

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

3
Ini mungkin solusi yang paling mudah dibaca yang diberikan. Saya akan mengubah kasus ProjectFilesmenjadi projectFiles, tapi solusi yang bagus.
Hans Goldman

42

Rangkai hasilnya:

import itertools as it, glob

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

Kemudian:

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

14
glob.glob -> glob.iglob sehingga rantai iterator sepenuhnya malas dievaluasi
rodrigob

1
Saya menemukan solusi yang sama tetapi tidak mengetahuinya chain.from_iterable. Jadi ini adalah serupa, tetapi kurang dibaca: it.chain(*(glob.iglob(pattern) for pattern in patterns)).
florisla

21

Begitu banyak jawaban yang menyarankan penggabungan sebanyak jumlah ekstensi, saya lebih suka menggembung sekali saja:

from pathlib import Path

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

15

dengan glob itu tidak mungkin. Anda hanya dapat menggunakan:
* cocok dengan semuanya
? cocok dengan karakter tunggal
[seq] yang cocok dengan karakter apa pun dalam seq
[! seq] cocok dengan karakter apa pun yang tidak dalam urutan

gunakan os.listdir dan regexp untuk memeriksa pola:

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

11
akhiri regex Anda dengan $ untuk mencocokkan hanya akhir nama file
ThiefMaster

1
Saya suka pendekatan ini - jika ekspresi glob tidak cukup kuat, tingkatkan ke sistem regex yang lebih kuat, jangan retas menggunakan misalnya itertoolskarena perubahan pola selanjutnya juga harus diretas (katakanlah Anda ingin mengizinkan huruf besar dan kecil) . Oh, dan mungkin lebih bersih untuk menulis'.*\.(txt|sql)'
metakermit

Apakah ada alasan untuk memilih os.listdir ('.') Daripada glob.iglob (' . ')?
Tn. WorshipMe

15

Misalnya, untuk *.mp3dan *.flacdi beberapa folder, Anda dapat melakukan:

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

Idenya dapat diperluas ke lebih banyak ekstensi file, tetapi Anda harus memeriksa bahwa kombinasi tidak akan cocok dengan ekstensi file yang tidak diinginkan lainnya yang mungkin Anda miliki di folder tersebut. Jadi berhati - hatilah dengan ini.

Untuk secara otomatis menggabungkan daftar sembarang ekstensi ke dalam satu pola glob, Anda dapat melakukan hal berikut:

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

A one-liner, Hanya untuk itu ..

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]

keluaran:

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

6

Meskipun glob default Python tidak benar-benar mengikuti setelah glob Bash, Anda dapat melakukannya dengan library lain. Kami dapat mengaktifkan kawat gigi di glob wcmatch .

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

Anda bahkan dapat menggunakan pola glob yang diperluas jika itu adalah preferensi Anda:

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

Ini tidak mengambil recursivebendera
Shamoon

@Shamoon Tidak, ia mengambil glob.GLOBSTARbenderanya
tak berwajah

4

Setelah datang ke sini untuk meminta bantuan, saya membuat solusi sendiri dan ingin membagikannya. Ini didasarkan pada jawaban user2363986, tapi menurut saya ini lebih terukur. Artinya, jika Anda memiliki 1000 ekstensi, kodenya akan tetap terlihat elegan.

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

Tidak berhasil untuk saya. Saya menggunakandirectoryPath = "/Users/bla/bla/images_dir*."
NeStack

Saya memerlukan info lebih lanjut untuk men-debug ini untuk Anda ... Apakah Anda mendapatkan pengecualian? Juga, jika Anda menggunakan Windows, jalur itu sepertinya tidak akan berfungsi (huruf drive hilang).
Hans Goldman

4

Berikut adalah varian pemahaman daftar satu baris dari jawaban Pat (yang juga termasuk yang Anda ingin gabungkan dalam direktori proyek tertentu):

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

Anda mengulang ekstensi ( for ext in exts), dan kemudian untuk setiap ekstensi Anda mengambil setiap file yang cocok dengan pola glob ( for f in glob.glob(os.path.join(project_dir, ext)).

Solusi ini singkat , dan tanpa loop-for yang tidak perlu, pemahaman daftar bersarang, atau fungsi untuk mengacaukan kode. Zen yang murni, ekspresif, dan pythonic .

Solusi ini memungkinkan Anda memiliki daftar kustom extsyang dapat diubah tanpa harus memperbarui kode Anda. (Ini selalu merupakan praktik yang baik!)

Pemahaman daftar sama dengan yang digunakan dalam solusi Laurent (yang saya pilih). Tetapi saya berpendapat bahwa biasanya tidak perlu memfaktorkan satu baris ke fungsi terpisah, itulah sebabnya saya memberikan ini sebagai solusi alternatif.

Bonus:

Jika Anda tidak hanya perlu mencari satu direktori, tetapi juga semua sub-direktori, Anda dapat meneruskan recursive=Truedan menggunakan simbol glob multi-direktori ** 1 :

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

Ini akan memanggil glob.glob('<project_dir>/**/*.txt', recursive=True)dan seterusnya untuk setiap ekstensi.

1 Secara teknis, **simbol bola hanya cocok dengan satu atau lebih karakter termasuk garis miring / (tidak seperti simbol bola tunggal *). Dalam praktiknya, Anda hanya perlu mengingat bahwa selama Anda mengapit **garis miring ke depan (pemisah jalur), itu cocok dengan nol atau lebih direktori.


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

4
Jawaban yang baik juga memberikan penjelasan tentang kode dan bahkan mungkin beberapa alasan Anda di balik kode tersebut.
SunSparc

3

Saya telah merilis Formic yang mengimplementasikan beberapa penyertaan dengan cara yang mirip dengan FileSet dan Globs Apache Ant .

Pencarian dapat dilakukan:

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

Karena Ant glob lengkap diimplementasikan, Anda dapat menyertakan direktori yang berbeda dengan setiap pola, sehingga Anda hanya dapat memilih file .txt tersebut dalam satu subdirektori, dan .markdown di subdirektori lainnya, misalnya:

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

Saya harap ini membantu.


3

Fungsi berikut berfungsi _globuntuk beberapa ekstensi file.

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

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

Juga mengabaikan semua nama file yang dimulai dengan ~.


2

Tidak glob, tapi inilah cara lain menggunakan pemahaman daftar:

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

1

Anda dapat mencoba membuat daftar manual yang membandingkan ekstensi yang ada dengan yang Anda butuhkan.

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

Untuk globbeberapa jenis file, Anda perlu memanggil glob()fungsi beberapa kali dalam satu putaran. Karena fungsi ini mengembalikan daftar, Anda perlu menggabungkan daftar.

Misalnya, fungsi ini melakukan pekerjaan:

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

Penggunaan sederhana:

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

Anda juga dapat menggunakan glob.iglob()untuk memiliki iterator:

Kembalikan iterator yang menghasilkan nilai yang sama dengan glob () tanpa benar-benar menyimpan semuanya secara bersamaan.

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

1

Gunakan daftar ekstensi dan lakukan iterasi

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

Anda bisa menggunakan filter:

import os
import glob

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

0

Anda juga bisa menggunakan reduce()seperti ini:

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

ini membuat daftar dari glob.glob()untuk setiap pola dan menguranginya menjadi satu daftar.


0

Satu glob, banyak ekstensi ... tetapi solusi yang tidak sempurna (mungkin cocok dengan file lain).

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

Saya memiliki masalah yang sama dan inilah yang saya temukan

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

Namun solusi lain (gunakan globuntuk mendapatkan jalur menggunakan banyak kecocokan patternsdan gabungkan semua jalur menjadi satu daftar menggunakan reducedan add):

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

0

Jika Anda menggunakan pathlibcoba ini:

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

Dari hasil yang saya peroleh dari uji empiris, ternyata itu glob.globbukan cara yang lebih baik untuk menyaring file dengan ekstensinya. Beberapa alasannya adalah:

  • " Bahasa " globbing tidak memungkinkan spesifikasi yang sempurna untuk beberapa ekstensi.
  • Hasil poin sebelumnya dalam mendapatkan hasil yang salah tergantung pada ekstensi file.
  • Metode global secara empiris terbukti lebih lambat dari kebanyakan metode lainnya.
  • Meskipun aneh, bahkan objek sistem file lain dapat memiliki " ekstensi ", folder juga.

Saya telah menguji (untuk kebenaran dan efisiensi waktu) 4berbagai metode berikut untuk memfilter file berdasarkan ekstensi dan menempatkannya di 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

Dengan menjalankan kode di atas di laptop saya, saya memperoleh hasil auto-explicative berikut.

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.

Cara tercepat untuk memfilter file berdasarkan ekstensi, bahkan bisa menjadi yang paling jelek. Yaitu, forloop bersarang dan stringperbandingan menggunakan endswith()metode.

Selain itu, seperti yang Anda lihat, algoritme globbing (dengan pola E:\x\y\z\**/*[py][pyc]) bahkan dengan 2ekstensi yang diberikan ( pydan pyc) juga mengembalikan hasil yang salah.


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)

Hai Sway Wu, selamat datang. Harap pertimbangkan untuk menambahkan penjelasan.
Tiago Martins Peres 李大仁

0

Dari jawaban sebelumnya

glob('*.jpg') + glob('*.png')

Ini yang lebih pendek,

from glob import glob
extensions = ['jpg', 'png'] # to find these filename extensions

# Method 1: loop one by one and extend to the output list
output = []
[output.extend(glob(f'*.{name}')) for name in extensions]
print(output)

# Method 2: even shorter
# loop filename extension to glob() it and flatten it to a list
output = [p for p2 in [glob(f'*.{name}') for name in extensions] for p in p2]
print(output)

2
Menambahkan penjelasan ke contoh kode ini akan membantu meningkatkan jawaban ini.
shinjw

-1

Ini Seharusnya Berhasil:

import glob
extensions = ('*.txt', '*.mdown', '*.markdown')
for i in extensions:
    for files in glob.glob(i):
        print (files)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.