这就是我所拥有的:
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'))
但这显然是有限且笨重的。
这就是我所拥有的:
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'))
但这显然是有限且笨重的。
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
解决方案。
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))
对于 python >= 3.5,您可以使用**
, recursive=True
:
import glob
for f in glob.glob('/path/**/*.c', recursive=True):
print(f)
如果递归是
True
,则该模式**
将匹配任何文件和零个或多个directories
和subdirectories
。如果模式后跟一个os.sep
, 只有目录和subdirectories
匹配。
与其他解决方案类似,但使用 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
此外,使用生成器可以让您在找到每个文件时对其进行处理,而不是查找所有文件然后处理它们。
我已经修改了 glob 模块以支持 ** 进行递归通配,例如:
>>> import glob2
>>> all_header_files = glob2.glob('src/**/*.c')
https://github.com/miracle2k/python-glob2/
当您希望为用户提供使用 ** 语法的能力时很有用,因此单独使用 os.walk() 还不够好。
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.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')
这就像在给定的相对模式之前调用
Path.glob()
with"**/"
added:
import pathlib
for p in pathlib.Path("src").rglob("*.c"):
print(p)
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')
: 同 1glob.glob('**/*.c')
: 匹配所有以.c
直接子目录结尾的文件,但不匹配当前目录glob.glob('*.c',recursive=True)
: 同 1glob.glob('*/*.c',recursive=True)
: 同 3glob.glob('**/*.c',recursive=True)
:匹配.c
以当前目录和所有子目录结尾的所有文件最近我不得不用扩展名 .jpg 恢复我的照片。我运行 photorec 并恢复了 4579 个目录,其中包含 220 万个文件,扩展名种类繁多。使用下面的脚本,我能够在几分钟内选择 50133 个具有 .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)
根据其他答案,这是我当前的工作实现,它检索根目录中的嵌套 xml 文件:
files = []
for root, dirnames, filenames in os.walk(myDir):
files.extend(glob.glob(root + "/*.xml"))
我真的很喜欢 python :)
万一这可能会让任何人感兴趣,我已经介绍了前三种建议的方法。我在 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)
我得到的结果是:
os_walk: ~3.6sec
rglob ~14.5sec
iglob: ~16.9sec
平台:Ubuntu 16.04、x86_64(核心i7)、
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.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'
仅使用 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
或者使用列表理解:
>>> 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 或 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)
除了适合一行并避免内存中不必要的列表之外,这还具有很好的副作用,您可以以类似于 ** 运算符的方式使用它,例如,您可以使用os.path.join(root, 'some/path/*.c')
它来获取所有 .c 文件具有此结构的 src 的子目录。
这是 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)
希望这可以帮助那些在类似问题上苦苦挣扎的人。
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']
这是我使用列表理解在目录和所有子目录中递归搜索多个文件扩展名的解决方案:
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
如果文件位于远程文件系统或存档中,则可以使用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 文档。
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)
我修改了这篇文章中的最佳答案.. 并且最近创建了这个脚本,它将遍历给定目录 (searchdir) 中的所有文件及其下的子目录...并打印文件名、根目录、修改/创建日期和尺寸。
希望这对某人有所帮助......他们可以浏览目录并获取文件信息。
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))
这是一个将模式与完整路径匹配的解决方案,而不仅仅是基本文件名。
它用于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
我需要一个适用于大型目录的python 2.x解决方案。
我同意这个:
import subprocess
foundfiles= subprocess.check_output("ls src/*.c src/**/*.c", shell=True)
for foundfile in foundfiles.splitlines():
print foundfile
请注意,如果ls
找不到任何匹配的文件,您可能需要一些异常处理。