这是我所拥有的:

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


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

#1 楼

pathlib.Path.rglob
使用来自Python 3.5中引入的pathlib.Path.rglob模块中的pathlib
from pathlib import Path

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

如果不想使用pathlib,可以使用glob.glob('**/*.c'),但不要别忘了传入关键字recursive,它将在大型目录上花费过多的时间。
如果匹配的文件以点开头(.),例如当前目录中的文件或基于Unix的系统上的隐藏文件,请使用下面的os.walk解决方案。对于较早的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))


评论


对于2.2之前的Python,存在os.path.walk(),它比os.walk()更有趣。

– John La Rooy
2010-2-2在19:34

@gnibbler我知道这是一个旧注释,但是我的注释只是让人们知道os.path.walk()已被弃用,并已在Python 3中删除。

– Pedro Cunha
13年1月18日在16:14

@DevC可能在此问题中遇到的特定情况下有效,但是很容易想象有人想要在查询中使用它,例如“ a * .c”等,因此我认为值得保留目前有些慢的答案。

–约翰·达林(Johan Dahlin)
2014年5月19日在19:29

就其价值而言,以我为例,使用glob查找10,000+个文件比使用os.walk要慢得多,因此出于这个原因,我选择了后一种解决方案。

–戈德史密斯
18年9月12日在6:23

对于python 3.4,pathlib.Path('src')。glob('** / *。c')应该可以工作。

– CivFan
19年4月11日,0:16

#2 楼

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

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 楼

我修改了glob模块以支持**用于递归glob,例如:

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


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

在希望为用户提供使用**语法的功能时很有用,因此仅os.walk()不够好。

评论


找到第一场比赛后,我们可以停下来吗?也许有可能将其用作生成器,而不是让它返回所有可能结果的列表?另外,这是DFS还是BFS?我认为我更希望使用BFS,以便首先找到根目录附近的文件。 +1用于制作此模块并将其提供到GitHub / pip。

–ArtOfWarfare
2014年8月5日在18:24

**语法已添加到Python 3.5中的官方glob模块中。

–ArtOfWarfare
15年1月26日在19:13

@ArtOfWarfare好吧。 <3.5仍然有用。

–cs95
17年7月3日在14:42

要使用带有官方glob模块的**激活递归glob,请执行以下操作:glob(path,recursive = True)

–winklerrr
3月29日11:09



#4 楼

从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()也支持语法。

评论


实际上,它将在Python 3.5中进行。在Python 3.4中本来应该是这样,但是被错误地省略了。

–taleinat
2015年2月24日在17:39



从Python 3.5开始,glob.glob()现在支持此语法。

–taleinat
15年8月4日在15:20

请注意,您也可以结合使用pathlib.PurePath.relative_to来获取相对路径。有关更多背景信息,请参见此处。

– pjgranahan
17年4月24日在23:11

#5 楼

对于python> = 3.5,可以使用**recursive=True
import glob
for x in glob.glob('/path/**/*.c', recursive=True):
    print(x)

Demo



如果递归是True,则模式**将匹配任何文件并且为零
或更多directoriessubdirectories。如果模式后面跟随有
os.sep,则仅目录和subdirectories匹配。


注意:
使用Python3.6时,recursive=True似乎默认为**,因此可以
演示Python 3.6

评论


这比pathlib.Path('./ path /')。glob('* /')更好,因为在大小为0的文件夹中也是如此

–查尔斯·沃克(Charles Walker)
4月18日15:14

这应该是最重要的答案

–乔纳森·R
9月3日10:59

#6 楼

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只需返回一个结果列表就可以返回)。

评论


如我在编辑中建议的那样,您如何看待使用recursive_glob(pattern,treeroot ='。')?这样,可以将其称为recursive_glob('*。txt')并直观地匹配glob的语法。

–克里斯·雷德福(Chris Redford)
15年1月4日在21:07

@ChrisRedford,无论哪种方式,我都认为这是一个很小的问题。目前,它与fnmatch.filter的“文件然后模式”参数顺序匹配,这与匹配单参数glob.glob的可能性大致一样有用。

– Alex Martelli
15年1月4日在21:43

#7 楼

您将要使用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 楼

这是一个具有嵌套列表推导,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')


如果确实需要完整的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')


#9 楼

考虑pathlib.rglob()


就像调用Path.glob()并在给定相对模式前面添加"**/"一样:


import pathlib


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


另请参阅@taleinat的相关文章和其他地方的类似文章。

#10 楼

最近,我不得不恢复扩展名为.jpg的图片。我运行了photorec并恢复了4579个目录,其中220万个文件具有多种扩展名。使用以下脚本,我可以在几分钟内选择50133个文件具有havin .jpg扩展名:

#!/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)


#11 楼

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

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


我真的很喜欢python:)

#12 楼

Johan和Bruno针对上述最低要求提供了出色的解决方案。我刚刚发布了实现了Ant FileSet和Globs的Formic,它们可以处理这种情况以及更复杂的情况。您的要求的实现是:

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


评论


甲酸似乎被遗弃了?!而且它不支持Python 3(bitbucket.org/aviser/formic/issue/12/support-python-3)

–蓝色
2014年9月4日,下午3:53

#13 楼

对于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'


评论


您的第一行代码不适用于查看子目录。但是,如果仅将它扩展为/ **,则对我有用,就像这样:file_names_array = glob.glob('src / ** / *。c',recursive = True)

– NeStack
19年8月28日在12:45

#14 楼

仅使用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


#15 楼

或具有列表理解:

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


#16 楼

 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') :与1

glob.glob('**/*.c') 相同:仅匹配直接子目录中所有以.c结尾的文件,但不匹配当前目录中的所有文件

glob.glob('*.c',recursive=True) :与1
<相同br /> glob.glob('*/*.c',recursive=True) :与3相同

glob.glob('**/*.c',recursive=True) :匹配当前目录和所有子目录中所有以.c结尾的文件


#17 楼

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

,但是我没有使用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)


#18 楼

使用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')])


#19 楼

除了建议的答案外,您还可以通过一些懒惰的生成和列表理解魔术来做到这一点:

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')来获取src的所有子目录中具有此结构的所有.c文件。 >

#20 楼

Johan Dahlin答案的简化版本,没有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']


#21 楼

这是我的使用列表推导的解决方案来在目录和所有子目录中递归搜索多个文件扩展名的方法:

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


#22 楼

这是Python 2.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)


希望对某人有帮助遇到类似问题。

#23 楼

万一这可能使任何人感兴趣,我已经介绍了建议的前三种方法。
我在全局文件夹中总共有约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)

我得到的结果是:os_walk:〜3.6sec
rglob〜14.5sec
平台:Ubuntu 16.04,x86_64(核心i7),

评论


老板。谢谢你

–研究人员
9月20日23:06

#24 楼

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)


#25 楼

我修改了此发布中的最佳答案..并最近创建了此脚本,该脚本将遍历给定目录(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))


#26 楼

这是一个将模式与完整路径而不是仅与基本文件名匹配的解决方案。

它使用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


#27 楼

如果文件位于远程文件系统上或存档中,则可以使用fsspec AbstractFileSystem类的实现。例如,要列出一个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/**")
 

其他实现包括Google Cloud,Github,SFTP / SSH,Dropbox和Azure。有关详细信息,请参见fsspec API文档。

#28 楼

我需要适用于大型目录的快速运行的python 2.x解决方案。
我总结了一下:

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


请注意,您可能需要一些例外处理ls找不到任何匹配的文件。

评论


我只是意识到ls src / ** / *。c仅在启用了globstar选项(shopt -s globstar)后才有效-有关详细信息,请参见此答案。

–罗马
17年6月27日在13:44

如果想快速运行,子进程永远不是一个好的解决方案,脚本中的ls绝对是要避免的事情。

–tripleee
12月18日13:46



好的,我对此一无所知。它对我有用-花费不到一秒钟的时间(而不是超过30秒...)

–罗马
12月19日15:39