Python toàn cầu nhiều kiểu


142

Có cách nào tốt hơn để sử dụng global.glob trong python để có danh sách nhiều loại tệp như .txt, .mdown và .markdown không? Ngay bây giờ tôi có một cái gì đó như thế này:

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

Câu trả lời:


156

Có thể có một cách tốt hơn, nhưng làm thế nào về:

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

Có lẽ có một cách khác, vì vậy hãy chờ đợi trong trường hợp người khác đưa ra câu trả lời tốt hơn.


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

10
Giải pháp của Novitoll ngắn, nhưng cuối cùng lại tạo ra các danh sách lồng nhau.
cướp

9
bạn luôn có thể làm điều này;)[f for f_ in [glob.glob(e) for e in ('*.jpg', '*.mp4')] for f in f_]
AlexG

1
files_grabbed = [ contin.glob (e) cho e trong [' .pdf', '* .cpp']]
florisla

3
Vòng lặp này hai lần thông qua danh sách các tập tin. Trong lần lặp đầu tiên, nó kiểm tra * .pdf và trong lần lặp thứ hai, nó kiểm tra * .cpp. Có cách nào để hoàn thành nó trong một lần lặp không? Kiểm tra điều kiện kết hợp mỗi lần?
Ridhuvarshan

47
from glob import glob

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

print(files)

Nếu bạn cần chỉ định một đường dẫn, lặp lại các mẫu khớp và giữ cho phép nối bên trong vòng lặp cho đơn giản:

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)

44

glob trả về một danh sách: tại sao không chạy nó nhiều lần và nối các kết quả?

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

2
Đây có thể là giải pháp dễ đọc nhất được đưa ra. Tôi sẽ thay đổi trường hợp của ProjectFilesđể projectFiles, nhưng giải pháp tuyệt vời.
Hans Goldman

40

Chuỗi kết quả:

import itertools as it, glob

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

Sau đó:

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

13
global.glob -> global.iglob để chuỗi lặp được đánh giá hoàn toàn lười biếng
Rodrigob

1
Tôi tìm thấy giải pháp tương tự nhưng không biết về chain.from_iterable. Vì vậy, điều này là tương tự, nhưng ít đọc hơn : it.chain(*(glob.iglob(pattern) for pattern in patterns)).
florisla

17

Vì vậy, rất nhiều câu trả lời đề xuất toàn cầu nhiều lần số lần mở rộng, thay vào đó tôi thích toàn cầu hóa hơn một lần:

from pathlib import Path

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

15

với toàn cầu thì không thể. bạn chỉ có thể sử dụng:
* phù hợp với mọi thứ
? phù hợp với bất kỳ nhân vật duy nhất
[seq] phù hợp với bất kỳ nhân vật nào trong seq
[! seq] phù hợp với bất kỳ nhân vật nào không có trong seq

sử dụng os.listdir và biểu thức chính quy để kiểm tra các mẫu:

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

10
kết thúc regex của bạn bằng $ để chỉ khớp với phần cuối của tên tệp
ThiefMaster

1
Tôi thích cách tiếp cận này - nếu tính biểu cảm của toàn cầu không đủ mạnh, hãy nâng cấp lên hệ thống regex mạnh hơn, đừng hack nó bằng cách sử dụng, itertoolsvì các thay đổi mẫu tiếp theo cũng phải được hack (giả sử bạn muốn cho phép viết hoa và viết thường) . Ồ, và nó có thể sạch hơn để viết'.*\.(txt|sql)'
metakermit

Có bất kỳ lý do nào để thích os.listdir ('.') Hơn global.iglob (' . ') Không?
Mr.WourMe

14

Ví dụ: cho *.mp3*.flactrên nhiều thư mục, bạn có thể làm:

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

Ý tưởng có thể được mở rộng cho nhiều phần mở rộng tệp hơn, nhưng bạn phải kiểm tra xem các kết hợp sẽ không khớp với bất kỳ phần mở rộng tệp không mong muốn nào khác mà bạn có thể có trên các thư mục đó. Vì vậy, hãy cẩn thận với điều này.

Để tự động kết hợp một danh sách các tiện ích mở rộng tùy ý thành một mẫu toàn cầu duy nhất, bạn có thể làm như sau:

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

Một lót, Chỉ cho địa ngục của nó ..

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]

đầu ra:

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

4

Sau khi đến đây để được giúp đỡ, tôi đã đưa ra giải pháp của riêng mình và muốn chia sẻ nó. Nó dựa trên câu trả lời của user2363986, nhưng tôi nghĩ rằng điều này có khả năng mở rộng hơn. Có nghĩa là, nếu bạn có 1000 tiện ích mở rộng, mã sẽ vẫn có vẻ thanh lịch.

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

Không làm việc cho tôi. Tôi sử dụngdirectoryPath = "/Users/bla/bla/images_dir*."
NeStack

Tôi sẽ cần thêm thông tin để gỡ lỗi này cho bạn ... Bạn có nhận được ngoại lệ không? Ngoài ra, nếu bạn đang ở trên Windows, đường dẫn đó không giống như nó sẽ hoạt động (thiếu ký tự ổ đĩa).
Hans Goldman

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

4
Câu trả lời tốt cũng cung cấp một số giải thích về mã và thậm chí có thể một số lý do của bạn đằng sau mã.
SunSparc

4

Trong khi toàn cầu mặc định của Python không thực sự theo sau toàn cầu của Bash, bạn có thể làm điều này với các thư viện khác. Chúng tôi có thể kích hoạt niềng răng trên toàn cầu của wcmatch .

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

Bạn thậm chí có thể sử dụng các mẫu toàn cầu mở rộng nếu đó là sở thích của bạn:

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

Điều này không có recursivecờ
Shamoon

@Shamoon Không, phải mất glob.GLOBSTARcờ
faclessuser

3

Tôi đã phát hành Formic , thực hiện nhiều phần bao gồm theo cách tương tự với Tập tin và Globs của Apache Ant .

Việc tìm kiếm có thể được thực hiện:

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

Vì toàn cầu Ant được triển khai, bạn có thể bao gồm các thư mục khác nhau với mỗi mẫu, do đó bạn chỉ có thể chọn các tệp .txt đó trong một thư mục con và .markdown trong một thư mục khác, ví dụ:

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

Tôi hi vọng cái này giúp được.


3

Các chức năng sau đây _globảm đạm cho nhiều phần mở rộng tập tin.

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

Đây là một pathlibgiải pháp Python 3,4+ :

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

Ngoài ra, nó bỏ qua tất cả các tên tập tin bắt đầu với ~.


3

Dưới đây là biến thể hiểu danh sách một dòng của câu trả lời của Pat (cũng bao gồm rằng bạn muốn toàn cầu trong một thư mục dự án cụ thể):

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

Bạn lặp qua các phần mở rộng ( for ext in exts), và sau đó với mỗi phần mở rộng, bạn lấy từng tệp khớp với mẫu hình cầu ( for f in glob.glob(os.path.join(project_dir, ext)).

Giải pháp này ngắn và không có bất kỳ vòng lặp for không cần thiết nào, việc hiểu danh sách lồng nhau hoặc các hàm để làm lộn xộn mã. Chỉ thuần khiết, biểu cảm, pythonic Zen .

Giải pháp này cho phép bạn có một danh sách tùy chỉnh exts có thể thay đổi mà không phải cập nhật mã của bạn. (Đây luôn là một thực hành tốt!)

Việc hiểu danh sách được sử dụng tương tự trong giải pháp của Laurent (mà tôi đã bình chọn). Nhưng tôi sẽ lập luận rằng thường không cần thiết phải đưa ra một dòng duy nhất cho một chức năng riêng biệt, đó là lý do tại sao tôi cung cấp điều này như một giải pháp thay thế.

Tặng kem:

Nếu bạn cần tìm kiếm không chỉ một thư mục mà còn tất cả các thư mục con, bạn có thể vượt qua recursive=Truevà sử dụng ký hiệu toàn cầu đa thư mục ** 1 :

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

Điều này sẽ gọi glob.glob('<project_dir>/**/*.txt', recursive=True) và như vậy cho mỗi phần mở rộng.

1 Về mặt kỹ thuật, **biểu tượng toàn cầu chỉ đơn giản khớp với một hoặc nhiều ký tự bao gồm dấu gạch chéo về phía trước / (không giống như *biểu tượng hình cầu số ít ). Trong thực tế, bạn chỉ cần nhớ rằng miễn là bạn bao quanh **bằng dấu gạch chéo (dấu phân cách đường dẫn), nó khớp với 0 hoặc nhiều thư mục.


2

Không glob, nhưng đây là một cách khác bằng cách hiểu danh sách:

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

1

Bạn có thể thử tạo một danh sách thủ công so sánh phần mở rộng hiện có với những phần bạn yêu cầu.

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

Đến glob nhiều loại tệp, bạn cần gọiglob() hàm nhiều lần trong một vòng lặp. Vì hàm này trả về một danh sách, bạn cần nối các danh sách.

Ví dụ, chức năng này thực hiện công việc:

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

Cách sử dụng đơn giản:

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

Bạn cũng có thể dùng glob.iglob() để có một trình vòng lặp:

Trả về một trình vòng lặp mang lại các giá trị giống như global () mà không thực sự lưu trữ tất cả chúng cùng một lúc.

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

1

Sử dụng danh sách các phần mở rộng và lặp qua

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

Bạn có thể sử dụng bộ lọc:

import os
import glob

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

0

Bạn cũng có thể sử dụng reduce()như vậy:

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

điều này tạo ra một danh sách từ glob.glob()cho mỗi mẫu và giảm chúng thành một danh sách.


0

Một thế giới, nhiều phần mở rộng ... nhưng giải pháp không hoàn hảo (có thể khớp với các tệp khác).

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

Tôi đã có cùng một vấn đề và đây là những gì tôi nghĩ ra

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

Một giải pháp khác (sử dụng globđể có được các đường dẫn sử dụng nhiều kết hợp patternsvà kết hợp tất cả các đường dẫn vào một danh sách bằng cách sử dụng reduceadd):

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

0

Nếu bạn sử dụng pathlibhãy thử điều này:

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

Bằng các kết quả tôi thu được từ các thử nghiệm thực nghiệm, hóa ra đó glob.globkhông phải là cách tốt hơn để lọc các tệp bằng các tiện ích mở rộng của chúng. Một số lý do là:

  • Các globbing " ngôn ngữ " toàn cầu không cho phép đặc tả hoàn hảo của nhiều phần mở rộng.
  • Điểm trước đây dẫn đến việc có được kết quả không chính xác tùy thuộc vào phần mở rộng tệp.
  • Phương pháp Globing được chứng minh bằng thực nghiệm là chậm hơn so với hầu hết các phương pháp khác.
  • Ngay cả khi nó lạ, ngay cả các đối tượng hệ thống tập tin khác cũng có thể có " phần mở rộng ", các thư mục cũng vậy.

Tôi đã thử nghiệm (về tính chính xác và hiệu quả kịp thời) các 4phương pháp khác nhau sau đây để lọc các tệp theo tiện ích mở rộng và đặt chúng vào 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

Bằng cách chạy mã ở trên máy tính xách tay của tôi, tôi đã thu được các kết quả tự động sau đây.

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.

Cách nhanh nhất để lọc các tệp theo tiện ích mở rộng, thậm chí là xấu nhất. Đó là, các forvòng lặp lồng nhau và stringso sánh bằng cách sử dụngendswith() phương pháp.

Hơn nữa, như bạn có thể thấy, các thuật toán toàn cầu (với mẫu E:\x\y\z\**/*[py][pyc]) ngay cả khi chỉ có 2phần mở rộng được đưa ra ( pypyc) cũng trả về kết quả không chính xác.


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)

Xin chào Sway Wu, chào mừng bạn. Vui lòng xem xét thêm một lời giải thích.
Tiago Martins Peres

-1

Điều này nên làm việc:

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

-1

Ví dụ:

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

Một chức năng:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.