Programing

glob ()을 사용하여 파일을 재귀 적으로 찾는 방법은 무엇입니까?

crosscheck 2020. 10. 2. 21:33
반응형

glob ()을 사용하여 파일을 재귀 적으로 찾는 방법은 무엇입니까?


이것이 내가 가진 것입니다.

glob(os.path.join('src','*.c'))

하지만 src의 하위 폴더를 검색하고 싶습니다. 다음과 같이 작동합니다.

glob(os.path.join('src','*.c'))
glob(os.path.join('src','*','*.c'))
glob(os.path.join('src','*','*','*.c'))
glob(os.path.join('src','*','*','*','*.c'))

그러나 이것은 분명히 제한적이고 투박합니다.


Python 3.5 이상

새로운 파이썬을 사용 pathlib.Path.glob하고 있으므로 pathlib모듈 에서 사용해야 합니다.

from pathlib import Path

for filename in Path('src').glob('**/*.c'):
    print(filename)

pathlib를 사용하지 않으려면을 사용 glob.glob하고 recursive키워드 매개 변수 를 전달하는 것을 잊지 마십시오 .

점 (.);으로 시작하는 파일이 일치하는 경우 현재 디렉토리의 파일이나 Unix 기반 시스템의 숨겨진 파일과 같이 os.walk아래 솔루션을 사용하십시오 .

이전 Python 버전

이전 Python 버전의 경우를 사용 os.walk하여 디렉토리를 재귀 적으로 탐색 fnmatch.filter하고 간단한 표현식과 일치시킵니다.

import fnmatch
import os

matches = []
for root, dirnames, filenames in os.walk('src'):
    for filename in fnmatch.filter(filenames, '*.c'):
        matches.append(os.path.join(root, filename))

다른 솔루션과 유사하지만 os.walk가 이미 파일 이름을 나열했기 때문에 glob 대신 fnmatch.fnmatch를 사용합니다.

import os, fnmatch


def find_files(directory, pattern):
    for root, dirs, files in os.walk(directory):
        for basename in files:
            if fnmatch.fnmatch(basename, pattern):
                filename = os.path.join(root, basename)
                yield filename


for filename in find_files('src', '*.c'):
    print 'Found C source:', filename

또한 생성기를 사용하면 모든 파일 을 찾은 다음 처리하는 대신 발견 된대로 각 파일 처리 할 수 ​​있습니다.


재귀 globbing을 위해 **를 지원하도록 glob 모듈을 수정했습니다. 예 :

>>> import glob2
>>> all_header_files = glob2.glob('src/**/*.c')

https://github.com/miracle2k/python-glob2/

** 구문을 사용할 수있는 기능을 사용자에게 제공하려는 경우 유용하므로 os.walk ()만으로는 충분하지 않습니다.


Python 3.4부터 와일드 카드 를 지원 하는 새 pathlib 모듈 glob()Path클래스 중 하나의 메서드를 사용할 수 있습니다 . 예를 들면 :**

from pathlib import Path

for file_path in Path('src').glob('**/*.c'):
    print(file_path) # do whatever you need with these files

업데이트 : Python 3.5부터 동일한 구문이 glob.glob().


import os
import fnmatch


def recursive_glob(treeroot, pattern):
    results = []
    for base, dirs, files in os.walk(treeroot):
        goodfiles = fnmatch.filter(files, pattern)
        results.extend(os.path.join(base, f) for f in goodfiles)
    return results

fnmatch는와 정확히 동일한 패턴을 제공 glob하므로 glob.glob매우 가까운 의미 체계로 대체 할 수 있습니다. 반복적 버전 (예 : 생성기), IOW 대신을 (를 glob.iglob) 대체 하는 것은 사소한 조정입니다 ( 끝에 반환 할 단일 결과 목록을 사용하는 yield대신 진행하면서 중간 결과 extend).


os.walk기준과 일치하는 파일 이름을 수집하는 데 사용할 수 있습니다. 예를 들면 :

import os
cfiles = []
for root, dirs, files in os.walk('src'):
  for file in files:
    if file.endswith('.c'):
      cfiles.append(os.path.join(root, file))

다음은 중첩 된 목록 이해 os.walkglob다음 대신 간단한 접미사 일치를 사용 하는 솔루션 입니다 .

import os
cfiles = [os.path.join(root, filename)
          for root, dirnames, filenames in os.walk('src')
          for filename in filenames if filename.endswith('.c')]

한 줄로 압축 할 수 있습니다.

import os;cfiles=[os.path.join(r,f) for r,d,fs in os.walk('src') for f in fs if f.endswith('.c')]

또는 함수로 일반화 :

import os

def recursive_glob(rootdir='.', suffix=''):
    return [os.path.join(looproot, filename)
            for looproot, _, filenames in os.walk(rootdir)
            for filename in filenames if filename.endswith(suffix)]

cfiles = recursive_glob('src', '.c')

전체 glob스타일 패턴 이 필요한 경우 Alex와 Bruno의 예를 따라 다음을 사용할 수 있습니다 fnmatch.

import fnmatch
import os

def recursive_glob(rootdir='.', pattern='*'):
    return [os.path.join(looproot, filename)
            for looproot, _, filenames in os.walk(rootdir)
            for filename in filenames
            if fnmatch.fnmatch(filename, pattern)]

cfiles = recursive_glob('src', '*.c')

최근에 .jpg 확장자로 사진을 복구해야했습니다. 나는 photorec을 실행하고 그 안에서 220 만개의 파일을 복구 한 4579 개의 디렉토리를 엄청나게 다양한 확장자로 복구했습니다. 아래 스크립트를 사용하여 몇 분 안에 .jpg 확장자를 가진 50133 개의 파일을 선택할 수있었습니다.

#!/usr/binenv python2.7

import glob
import shutil
import os

src_dir = "/home/mustafa/Masaüstü/yedek"
dst_dir = "/home/mustafa/Genel/media"
for mediafile in glob.iglob(os.path.join(src_dir, "*", "*.jpg")): #"*" is for subdirectory
    shutil.copy(mediafile, dst_dir)

Johan과 Bruno는 언급 된 최소한의 요구 사항에 대한 탁월한 솔루션을 제공합니다. 저는이 문제와 더 복잡한 시나리오를 처리 할 수있는 Ant FileSet 및 Globs구현하는 Formic방금 출시했습니다 . 요구 사항의 구현은 다음과 같습니다.

import formic
fileset = formic.FileSet(include="/src/**/*.c")
for file_name in fileset.qualified_files():
    print file_name

다른 답변을 기반으로 이것은 루트 디렉토리에서 중첩 된 xml 파일을 검색하는 현재 작업 구현입니다.

files = []
for root, dirnames, filenames in os.walk(myDir):
    files.extend(glob.glob(root + "/*.xml"))

나는 정말 파이썬으로 재미있다 :)


고려하십시오 pathlib.rglob().

이것은 주어진 상대 패턴 앞에 add Path.glob()호출 하는 것과 같습니다 "**/".

import pathlib


for p in pathlib.Path("src").rglob("*.c"):
    print(p)

여기에서 @taleinat의 관련 게시물다른 곳 의 이전 게시물을 참조하십시오 .


glob 모듈을 사용하는 또 다른 방법입니다. 시작 기본 디렉토리와 일치시킬 패턴으로 rglob 메소드를 시드하면 일치하는 파일 이름 목록이 반환됩니다.

import glob
import os

def _getDirs(base):
    return [x for x in glob.iglob(os.path.join( base, '*')) if os.path.isdir(x) ]

def rglob(base, pattern):
    list = []
    list.extend(glob.glob(os.path.join(base,pattern)))
    dirs = _getDirs(base)
    if len(dirs):
        for d in dirs:
            list.extend(rglob(os.path.join(base,d), pattern))
    return list

방금 만든 .. 파일과 디렉토리를 계층 적으로 인쇄합니다.

하지만 fnmatch 나 walk를 사용하지 않았어요

#!/usr/bin/python

import os,glob,sys

def dirlist(path, c = 1):

        for i in glob.glob(os.path.join(path, "*")):
                if os.path.isfile(i):
                        filepath, filename = os.path.split(i)
                        print '----' *c + filename

                elif os.path.isdir(i):
                        dirname = os.path.basename(i)
                        print '----' *c + dirname
                        c+=1
                        dirlist(i,c)
                        c-=1


path = os.path.normpath(sys.argv[1])
print(os.path.basename(path))
dirlist(path)

그 사람은 fnmatch 또는 정규식을 사용합니다.

import fnmatch, os

def filepaths(directory, pattern):
    for root, dirs, files in os.walk(directory):
        for basename in files:
            try:
                matched = pattern.match(basename)
            except AttributeError:
                matched = fnmatch.fnmatch(basename, pattern)
            if matched:
                yield os.path.join(root, basename)

# usage
if __name__ == '__main__':
    from pprint import pprint as pp
    import re
    path = r'/Users/hipertracker/app/myapp'
    pp([x for x in filepaths(path, re.compile(r'.*\.py$'))])
    pp([x for x in filepaths(path, '*.py')])

제안 된 답변 외에도 지연 생성 및 목록 이해 마법으로이를 수행 할 수 있습니다.

import os, glob, itertools

results = itertools.chain.from_iterable(glob.iglob(os.path.join(root,'*.c'))
                                               for root, dirs, files in os.walk('src'))

for f in results: print(f)

Besides fitting in one line and avoiding unnecessary lists in memory, this also has the nice side effect, that you can use it in a way similar to the ** operator, e.g., you could use os.path.join(root, 'some/path/*.c') in order to get all .c files in all sub directories of src that have this structure.


For python >= 3.5 you can use **, recursive=True :

import glob
for x in glob.glob('path/**/*.c', recursive=True):
    print(x)

Demo


If recursive is true, the pattern ** will match any files and zero or more directories and subdirectories. If the pattern is followed by an os.sep, only directories and subdirectories match.


Simplified version of Johan Dahlin's answer, without fnmatch.

import os

matches = []
for root, dirnames, filenames in os.walk('src'):
  matches += [os.path.join(root, f) for f in filenames if f[-2:] == '.c']

Or with a list comprehension:

 >>> base = r"c:\User\xtofl"
 >>> binfiles = [ os.path.join(base,f) 
            for base, _, files in os.walk(root) 
            for f in files if f.endswith(".jpg") ] 

Here is my solution using list comprehension to search for multiple file extensions recursively in a directory and all subdirectories:

import os, glob

def _globrec(path, *exts):
""" Glob recursively a directory and all subdirectories for multiple file extensions 
    Note: Glob is case-insensitive, i. e. for '\*.jpg' you will get files ending
    with .jpg and .JPG

    Parameters
    ----------
    path : str
        A directory name
    exts : tuple
        File extensions to glob for

    Returns
    -------
    files : list
        list of files matching extensions in exts in path and subfolders

    """
    dirs = [a[0] for a in os.walk(path)]
    f_filter = [d+e for d in dirs for e in exts]    
    return [f for files in [glob.iglob(files) for files in f_filter] for f in files]

my_pictures = _globrec(r'C:\Temp', '\*.jpg','\*.bmp','\*.png','\*.gif')
for f in my_pictures:
    print f

import sys, os, glob

dir_list = ["c:\\books\\heap"]

while len(dir_list) > 0:
    cur_dir = dir_list[0]
    del dir_list[0]
    list_of_files = glob.glob(cur_dir+'\\*')
    for book in list_of_files:
        if os.path.isfile(book):
            print(book)
        else:
            dir_list.append(book)

I modified the top answer in this posting.. and recently created this script which will loop through all files in a given directory (searchdir) and the sub-directories under it... and prints filename, rootdir, modified/creation date, and size.

Hope this helps someone... and they can walk the directory and get fileinfo.

import time
import fnmatch
import os

def fileinfo(file):
    filename = os.path.basename(file)
    rootdir = os.path.dirname(file)
    lastmod = time.ctime(os.path.getmtime(file))
    creation = time.ctime(os.path.getctime(file))
    filesize = os.path.getsize(file)

    print "%s**\t%s\t%s\t%s\t%s" % (rootdir, filename, lastmod, creation, filesize)

searchdir = r'D:\Your\Directory\Root'
matches = []

for root, dirnames, filenames in os.walk(searchdir):
    ##  for filename in fnmatch.filter(filenames, '*.c'):
    for filename in filenames:
        ##      matches.append(os.path.join(root, filename))
        ##print matches
        fileinfo(os.path.join(root, filename))

Here is a solution that will match the pattern against the full path and not just the base filename.

It uses fnmatch.translate to convert a glob-style pattern into a regular expression, which is then matched against the full path of each file found while walking the directory.

re.IGNORECASE is optional, but desirable on Windows since the file system itself is not case-sensitive. (I didn't bother compiling the regex because docs indicate it should be cached internally.)

import fnmatch
import os
import re

def findfiles(dir, pattern):
    patternregex = fnmatch.translate(pattern)
    for root, dirs, files in os.walk(dir):
        for basename in files:
            filename = os.path.join(root, basename)
            if re.search(patternregex, filename, re.IGNORECASE):
                yield filename

I needed a solution for python 2.x that works fast on large directories.
I endet up with this:

import subprocess
foundfiles= subprocess.check_output("ls src/*.c src/**/*.c", shell=True)
for foundfile in foundfiles.splitlines():
    print foundfile

Note that you might need some exception handling in case ls doesn't find any matching file.


For python 3.5 and later

file_names_array = glob.glob('src/*.c', recursive=True)

Edit: As @NeStack guided if above does not work for you, please try

file_names_array = glob.glob('src/**.c', recursive=True)

further you might need

for full_path_in_src in  file_names_array:
    print (full_path_in_src ) # be like 'abc/xyz.c'
    #Full system path of this would be like => 'path till src/abc/xyz.c'

참고URL : https://stackoverflow.com/questions/2186525/how-to-use-glob-to-find-files-recursively

반응형