代码之家  ›  专栏  ›  技术社区  ›  Ben Gartner

如何使用glob()递归查找文件?

  •  568
  • Ben Gartner  · 技术社区  · 14 年前

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

    但这显然是有限和笨拙的。

    21 回复  |  直到 5 年前
        1
  •  1549
  •   Johan Dahlin Idelic    4 年前

    pathlib.Path.rglob

    pathlib.Path.rglob pathlib 模块,它是在Python 3.5中引入的。

    from pathlib import Path
    
    for path in Path('src').rglob('*.c'):
        print(path.name)
    

    如果不想使用pathlib,可以使用 glob.glob('**/*.c') recursive 关键字参数,它将在大目录上使用过多的时间。

    适用于以点开头的匹配文件的情况( . ); 与当前目录中的文件或基于Unix的系统上的隐藏文件类似,请使用 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))
    
        2
  •  118
  •   Johan Dahlin Idelic    13 年前

    与其他解决方案类似,但使用fnmatch.fnmatch而不是glob,因为os.WACK已经列出了文件名:

    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
    

    然后

        3
  •  84
  •   Matt user129975    9 年前

    我已经修改了glob模块,以支持**进行递归globbing,例如:

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

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

    当您希望为用户提供使用**语法的能力时,此功能非常有用,因此单靠os.walk()是不够的。

        4
  •  75
  •   taleinat    9 年前

    glob() 方法之一 Path pathlib 模块,它支持 ** 通配符。例如:

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

    更新: 从Python3.5开始,同样的语法也受 glob.glob()

        5
  •  69
  •   Pedro Lobito    3 年前

    对于python>= 3.5 你可以用 ** , recursive=True

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

    Demo


    如果递归是 True ,模式 将匹配任何文件和零 或更多 directories subdirectories . 如果模式后面是 一 os.sep 子目录 匹配。


    注:

    Python3.6 递归=真 使用时 ** 所以可以省略。

    Demo Python 3.6

        6
  •  40
  •   Sebastian Mach    10 年前
    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 语义非常接近。迭代版本(如发电机),用于替换 glob.iglob ,是一个微不足道的改编(只是 yield 中间结果随您进行,而不是 extend

        7
  •  21
  •   Geoff Reedy    14 年前

    你会想用 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))
    
        8
  •  16
  •   blueyed    10 年前

    os.walk 和简单的后缀匹配,而不是 glob :

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

    如果你真的需要 样式模式,你可以按照Alex的和 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')
    
        9
  •  9
  •   pylang    5 年前

    pathlib.rglob()

    这就像打电话一样 Path.glob() "**/" 在给定的相对模式前面添加:

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

    另见@taleinat的相关内容 post 这里和一个类似的 post 在别处

        10
  •  8
  •   Milovan TomaÅ¡ević    4 年前
    import os, glob
    
    for each in glob.glob('path/**/*.c', recursive=True):
        print(f'Name with path: {each} \nName without path: {os.path.basename(each)}')
    
    • glob.glob('*.c') :匹配以结尾的所有文件 .c 在当前目录中
    • glob.glob('*/*.c')
    • glob.glob('**/*.c') :匹配以结尾的所有文件 C
    • glob.glob('*.c',recursive=True) :与1相同
    • glob.glob('*/*.c',recursive=True) :与3相同
    • glob.glob('**/*.c',recursive=True) :匹配以结尾的所有文件 C 在当前目录和所有子目录中
        11
  •  7
  •   mmmmmm    12 年前

    #!/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)
    
        12
  •  6
  •   daveoncode    12 年前

    根据其他答案,这是我当前的工作实现,它检索根目录中的嵌套xml文件:

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

    我真的很喜欢python:)

        13
  •  5
  •   Andrew Alcock    12 年前

    Formic 哪个实现了Ant FileSet and Globs

    import formic
    fileset = formic.FileSet(include="/src/**/*.c")
    for file_name in fileset.qualified_files():
        print file_name
    
        14
  •  5
  •   Sami    5 年前

    适用于python 3.5及更高版本

    import glob
    
    #file_names_array = glob.glob('path/*.c', recursive=True)
    #above works for files directly at path/ as guided by NeStack
    
    #updated version
    file_names_array = glob.glob('path/**/*.c', recursive=True)
    

    您可能需要进一步的帮助

    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'
    
        15
  •  3
  •   chris-piekarski    13 年前

    另一种方法是只使用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
    
        16
  •  3
  •   xtofl Adam Rosenfield    11 年前

     >>> 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") ] 
    
        17
  •  3
  •   Daniel    4 年前

    如果有人对此感兴趣,我已经简要介绍了三种建议的方法。 我在globbed文件夹中有大约500K个文件(总共),还有2K个与所需模式匹配的文件。

    下面是(非常基本的)代码

    import glob
    import json
    import fnmatch
    import os
    from pathlib import Path
    from time import time
    
    
    def find_files_iglob():
        return glob.iglob("./data/**/data.json", recursive=True)
    
    
    def find_files_oswalk():
        for root, dirnames, filenames in os.walk('data'):
            for filename in fnmatch.filter(filenames, 'data.json'):
                yield os.path.join(root, filename)
    
    def find_files_rglob():
        return Path('data').rglob('data.json')
    
    t0 = time()
    for f in find_files_oswalk(): pass    
    t1 = time()
    for f in find_files_rglob(): pass
    t2 = time()
    for f in find_files_iglob(): pass 
    t3 = time()
    print(t1-t0, t2-t1, t3-t2)
    


    步行时间:约3.6秒
    rglob~14.5秒
    iglob:~16.9秒

    平台:Ubuntu 16.04,x86_64(core i7),

        18
  •  2
  •   Shaurya Gupta    11 年前

    刚做了这个。。它将以分层方式打印文件和目录

    但我没有比赛或走路

    #!/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)
    
        19
  •  2
  •   hipertracker    11 年前

    使用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')])
    
        20
  •  2
  •   f0xdx    9 年前

    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)
    

    os.path.join(root, 'some/path/*.c')

        21
  •  2
  •   Sanjay Bharwani    4 年前

    这是Python2.7上的工作代码。作为devops工作的一部分,我需要编写一个脚本,将标有live-appName.properties的配置文件移动到appName.properties。可能还有其他扩展文件,如live-appName.xml。

    下面是这方面的工作代码,它在给定目录(嵌套级别)中查找文件,然后将其重命名(移动)为所需的文件名

    def flipProperties(searchDir):
       print "Flipping properties to point to live DB"
       for root, dirnames, filenames in os.walk(searchDir):
          for filename in fnmatch.filter(filenames, 'live-*.*'):
            targetFileName = os.path.join(root, filename.split("live-")[1])
            print "File "+ os.path.join(root, filename) + "will be moved to " + targetFileName
            shutil.move(os.path.join(root, filename), targetFileName)
    

    flipProperties(searchDir)
    

    希望这有助于解决类似问题的人。

        22
  •  1
  •   flowfree    11 年前

    约翰·达林答案的简化版本,没有 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']
    
        23
  •  1
  •   sackpower    10 年前

    下面是我使用列表理解搜索的解决方案 倍数 递归地 在目录和所有子目录中:

    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
    
        24
  •  1
  •   gerrit    4 年前

    远程文件系统 ,您可以使用 fsspec AbstractFileSystem class . 例如,要列出zipfile中的所有文件,请执行以下操作:

    from fsspec.implementations.zip import ZipFileSystem
    fs = ZipFileSystem("/tmp/test.zip")
    fs.glob("/**")  # equivalent: fs.find("/")
    

    或者列出公开可用S3存储桶中的所有文件:

    from s3fs import S3FileSystem
    fs_s3 = S3FileSystem(anon=True)
    fs_s3.glob("noaa-goes16/ABI-L1b-RadF/2020/045/**")  # or use fs_s3.find
    

    您还可以将其用于本地文件系统,如果您的实现与文件系统无关,这可能会很有趣:

    from fsspec.implementations.local import LocalFileSystem
    fs = LocalFileSystem()
    fs.glob("/tmp/test/**")
    

    其他实现包括谷歌云、Github、SFTP/SSH、Dropbox和Azure。有关详细信息,请参阅 fsspec API documentation .

        25
  •  0
  •   user1903204 user1903204    10 年前
    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)
    
        26
  •  0
  •   ihightower john    10 年前

    我修改了这篇帖子的答案。。最近创建了这个脚本,它将遍历给定目录(searchdir)中的所有文件及其子目录。。。并打印文件名、rootdir、修改/创建日期和大小。

    希望这对某人有帮助。。。他们可以浏览目录并获取文件信息。

    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))
    
        27
  •  0
  •   yoyo    9 年前

    下面是一个解决方案,它将根据完整路径而不仅仅是基本文件名匹配模式。

    它使用 fnmatch.translate 将glob样式模式转换为正则表达式,然后根据遍历目录时找到的每个文件的完整路径进行匹配。

    re.IGNORECASE 是可选的,但在Windows上是可取的,因为文件系统本身不区分大小写(我没有费心编译正则表达式,因为文档表明它应该在内部缓存。)

    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
    
        28
  •  -1
  •   Roman    7 年前

    Python2.x 快速的 在大目录上。
    我最后说:

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

    ls 找不到任何匹配的文件。