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

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

960120 次浏览

您需要使用os.walk来收集符合您的条件的文件名。例如:

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

pathlib.Path.rglob

使用Python 3.5中引入的pathlib模块中的pathlib.Path.rglob

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

如果您不想使用Pathlib,use可以使用glob.glob('**/*.c'),但不要忘记传入recursive关键字参数,它将在大型目录上使用过多的时间。

对于匹配以点(.)开头的文件的情况;例如当前目录中的文件或基于Unix的系统上的隐藏文件,请使用下面的os.walk解决方案。

os.walk

对于较旧的Python版本,使用os.walk递归遍历目录,使用fnmatch.filter匹配简单表达式:

import fnmatchimport os
matches = []for root, dirnames, filenames in os.walk('src'):for filename in fnmatch.filter(filenames, '*.c'):matches.append(os.path.join(root, filename))
import osimport 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最后返回单个结果列表)。

与其他解决方案类似,但使用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

此外,使用生成器可以让您在找到每个文件时处理它,而不是找到处理它们的所有文件然后

我已经修改了Globb模块以支持**递归全局化,例如:

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

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

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

另一种方法是仅使用Glob模块。只需使用起始基目录和要匹配的模式为rGlob方法播种,它将返回匹配文件名的列表。

import globimport 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

这里有一个嵌套列表推导的解决方案,os.walk和简单的后缀匹配而不是glob

import oscfiles = [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的和布鲁诺的例子和使用fnmatch

import fnmatchimport os
def recursive_glob(rootdir='.', pattern='*'):return [os.path.join(looproot, filename)for looproot, _, filenames in os.walk(rootdir)for filename in filenamesif fnmatch.fnmatch(filename, pattern)]
cfiles = recursive_glob('src', '*.c')

Johan和Bruno在所述的最低要求上提供了出色的解决方案。我刚刚发布了形式,它实现了能够处理这种和更复杂场景的蚂蚁FileSet和Globs。您的需求的实现是:

import formicfileset = 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"))

我真的很喜欢Python:)

最近我不得不用扩展名. jpg恢复我的照片。我运行Photorec并恢复了4579个目录220万文件,其中有各种各样的扩展名。使用下面的脚本,我能够在几分钟内选择50133个扩展名为. jpg的文件:

#!/usr/binenv python2.7
import globimport shutilimport 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 subdirectoryshutil.copy(mediafile, dst_dir)

约翰·达林答案的简化版本,没有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']

或者用列表理解:

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

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

但我没有用FNMatch或步行

#!/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 + dirnamec+=1dirlist(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)
# usageif __name__ == '__main__':from pprint import pprint as ppimport repath = 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 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)

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

import os, glob
def _globrec(path, *exts):""" Glob recursively a directory and all subdirectories for multiple file extensionsNote: Glob is case-insensitive, i. e. for '\*.jpg' you will get files endingwith .jpg and .JPG
Parameters----------path : strA directory nameexts : tupleFile extensions to glob for
Returns-------files : listlist 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

从Python 3.4开始,可以在新的Pathlib模块中使用Path类之一的glob()方法,它支持**通配符。例如:

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

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

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

import timeimport fnmatchimport 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 matchesfileinfo(os.path.join(root, filename))

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

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

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

import fnmatchimport osimport 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

除了建议的答案,你还可以用一些懒惰生成和列表理解魔法来做到这一点:

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文件。

我需要一个在大目录上工作快速python2. x解决方案。
我的回答是:

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

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

考虑pathlib.rglob()

这就像调用Path.glob(),在给定的相对模式前面添加"**/"

import pathlib

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

另见@taleinat的相关帖子在这里和类似的帖子在其他地方。

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

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

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

如果递归是True,模式**将匹配任何文件和零或者更多directoriessubdirectories。如果模式后面跟着os.sep,只有目录和subdirectories匹配。


Python 3.6演示

这是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 " + targetFileNameshutil.move(os.path.join(root, filename), targetFileName)

从主脚本调用此函数

flipProperties(searchDir)

希望这能帮助人们解决类似的问题。

如果有人对此感兴趣,我已经概述了前三个建议的方法。我有大约~500K文件在Globbeds文件夹(总共),和2K文件匹配所需的模式。

这是(非常基本的)代码

import globimport jsonimport fnmatchimport osfrom pathlib import Pathfrom 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(): passt1 = time()for f in find_files_rglob(): passt2 = time()for f in find_files_iglob(): passt3 = time()print(t1-t0, t2-t1, t3-t2)

我得到的结果是:
os_walk:~3.6秒
RGLOB~14.5sec
iglob:~16.9秒

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

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相同
  • glob.glob('*/*.c',recursive=True) :与3相同
  • glob.glob('**/*.c',recursive=True) :匹配当前目录和所有子目录中以.c结尾的所有文件

如果文件位于远程文件系统在档案上,您可以使用fsspec抽象文件系统类的实现。例如,要列出zipfile中的所有文件:

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

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

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

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

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

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