Answers:
在Python 3.5及更高版本中,使用新的递归**/
功能:
configfiles = glob.glob('C:/Users/sam/Desktop/file1/**/*.txt', recursive=True)
当recursive
被设置时,**
随后是路径分隔匹配0或多个子目录。
在早期的Python版本中,glob.glob()
无法递归列出子目录中的文件。
在这种情况下,我将改用os.walk()
结合fnmatch.filter()
:
import os
import fnmatch
path = 'C:/Users/sam/Desktop/file1'
configfiles = [os.path.join(dirpath, f)
for dirpath, dirnames, files in os.walk(path)
for f in fnmatch.filter(files, '*.txt')]
这将递归遍历您的目录,并将所有绝对路径名返回到匹配.txt
文件。在这种特定情况下,fnmatch.filter()
可能是矫kill过正,您也可以使用.endswith()
测试:
import os
path = 'C:/Users/sam/Desktop/file1'
configfiles = [os.path.join(dirpath, f)
for dirpath, dirnames, files in os.walk(path)
for f in files if f.endswith('.txt')]
path to directory
。
recursive=False
与**/
功能一起设置时不仅仅在给定文件夹中提供文件列表,而是在其子文件夹中提供文件列表?
**/
给出当前工作目录中的目录名称列表,因为该模式以结尾/
,并且recursive=False
您基本上有了一个double *
,匹配与相同*/
,效率更低。
*/*
如果需要所有子目录中的所有文件,请使用。
要在直接子目录中查找文件:
configfiles = glob.glob(r'C:\Users\sam\Desktop\*\*.txt')
对于遍历所有子目录的递归版本,您可以使用**
和传递recursive=True
自Python 3.5之后的版本:
configfiles = glob.glob(r'C:\Users\sam\Desktop\**\*.txt', recursive=True)
这两个函数调用都返回列表。您可以用来glob.iglob()
一一返回路径。或使用pathlib
:
from pathlib import Path
path = Path(r'C:\Users\sam\Desktop')
txt_files_only_subdirs = path.glob('*/*.txt')
txt_files_all_recursively = path.rglob('*.txt') # including the current dir
两种方法都返回迭代器(您可以一一获取路径)。
glob()
也支持目录中的模式。
**
递归案例的文档更新。但是**
要工作,您必须设置recursion=True
开关,顺便说一句。
在这个话题上有很多困惑。让我看看是否可以澄清它(Python 3.7):
glob.glob('*.txt') :
匹配当前目录中所有以“ .txt”结尾的文件glob.glob('*/*.txt') :
与1相同glob.glob('**/*.txt') :
仅匹配直接子目录中所有以'.txt'结尾的文件,而不匹配当前目录中的所有文件glob.glob('*.txt',recursive=True) :
与1相同glob.glob('*/*.txt',recursive=True) :
与3相同glob.glob('**/*.txt',recursive=True):
匹配当前目录和所有子目录中所有以“ .txt”结尾的文件所以最好总是指定 recursive=True.
该glob2包支持通配符和相当快
code = '''
import glob2
glob2.glob("files/*/**")
'''
timeit.timeit(code, number=1)
在我的笔记本电脑上,匹配> 60,000个文件路径大约需要2秒钟。
这是改编版,glob.glob
无需使用即可启用类似功能glob2
。
def find_files(directory, pattern='*'):
if not os.path.exists(directory):
raise ValueError("Directory not found {}".format(directory))
matches = []
for root, dirnames, filenames in os.walk(directory):
for filename in filenames:
full_path = os.path.join(root, filename)
if fnmatch.filter([full_path], pattern):
matches.append(os.path.join(root, filename))
return matches
因此,如果您具有以下目录结构
tests/files
├── a0
│ ├── a0.txt
│ ├── a0.yaml
│ └── b0
│ ├── b0.yaml
│ └── b00.yaml
└── a1
你可以做这样的事情
files = utils.find_files('tests/files','**/b0/b*.yaml')
> ['tests/files/a0/b0/b0.yaml', 'tests/files/a0/b0/b00.yaml']
几乎fnmatch
对整个文件名本身模式匹配,而不只是文件名。
如果您运行的是Python 3.4+,则可以使用该pathlib
模块。该Path.glob()
方法支持**
模式,即“递归该目录和所有子目录”。它返回一个生成器,生成Path
所有匹配文件的对象。
from pathlib import Path
configfiles = Path("C:/Users/sam/Desktop/file1/").glob("**/*.txt")
正如Martijn所指出的,glob只能通过**
Python 3.5中引入的运算符来做到这一点。由于OP明确要求使用glob模块,因此以下代码将返回行为类似的惰性评估迭代器
import os, glob, itertools
configfiles = itertools.chain.from_iterable(glob.iglob(os.path.join(root,'*.txt'))
for root, dirs, files in os.walk('C:/Users/sam/Desktop/file1/'))
请注意,configfiles
尽管如此,您只能在此方法中重复一次。如果您需要可在多个操作中使用的配置文件的真实列表,则必须使用创建显式的配置文件list(configfiles)
。
该命令rglob
将对目录结构的最深子级别进行无限递归。如果您只想深一层,则不要使用它。
我意识到OP正在谈论使用glob.glob。我相信,这可以回答意图,即递归搜索所有子文件夹。
该rglob
函数最近使数据处理算法的速度提高了100倍,该算法使用文件夹结构作为数据读取顺序的固定假设。但是,由于rglob
我们能够对指定父目录或该目录下的所有文件进行一次扫描,将它们的名称保存到列表(超过一百万个文件),然后使用该列表来确定我们需要在任何目录下打开哪些文件仅基于文件命名约定及其在哪个文件夹中指向将来。