我想在一个文件夹中打开一系列子文件夹并找到一些文本文件并打印一些文本文件的行。我正在使用这个:
configfiles = glob.glob('C:/Users/sam/Desktop/file1/*.txt')
但这也不能访问子文件夹。有谁知道我如何使用相同的命令来访问子文件夹?
我想在一个文件夹中打开一系列子文件夹并找到一些文本文件并打印一些文本文件的行。我正在使用这个:
configfiles = glob.glob('C:/Users/sam/Desktop/file1/*.txt')
但这也不能访问子文件夹。有谁知道我如何使用相同的命令来访问子文件夹?
在 Python 3.5 和更新版本中使用新的递归**/
功能:
configfiles = glob.glob('C:/Users/sam/Desktop/file1/**/*.txt', recursive=True)
recursive
设置时,**
后跟路径分隔符匹配 0 个或多个子目录。
在早期的 Python 版本中,glob.glob()
不能递归地列出子目录中的文件。
在那种情况下,我会使用os.walk()
组合 withfnmatch.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()
可能是矫枉过正,您也可以使用.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')]
关于这个话题有很多困惑。让我看看我是否可以澄清它(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.
在直接子目录中查找文件:
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
两种方法都返回迭代器(您可以一一获取路径)。
glob2包支持通配符并且相当快
code = '''
import glob2
glob2.glob("files/*/**")
'''
timeit.timeit(code, number=1)
在我的笔记本电脑上,匹配>60,000 个文件路径大约需要 2 秒。
您可以在 Python 2.6中使用Formic
import formic
fileset = formic.FileSet(include="**/*.txt", directory="C:/Users/sam/Desktop/")
披露 - 我是这个包的作者。
这是一个改编版本,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
整个文件名本身的模式匹配,而不仅仅是文件名。
configfiles = glob.glob('C:/Users/sam/Desktop/**/*.txt")
不适用于所有情况,而是使用 glob2
configfiles = glob2.glob('C:/Users/sam/Desktop/**/*.txt")
如果你可以安装 glob2 包...
import glob2
filenames = glob2.glob("C:\\top_directory\\**\\*.ext") # Where ext is a specific file extension
folders = glob2.glob("C:\\top_directory\\**\\")
所有文件名和文件夹:
all_ff = glob2.glob("C:\\top_directory\\**\\**")
如果您正在运行 Python 3.4+,则可以使用该pathlib
模块。该Path.glob()
方法支持该**
模式,这意味着“此目录和所有子目录,递归地”。它返回一个生成器,Path
为所有匹配的文件生成对象。
from pathlib import Path
configfiles = Path("C:/Users/sam/Desktop/file1/").glob("**/*.txt")
(第一个选项当然在其他答案中提到,这里的目标是显示 glob 在os.scandir
内部使用,并提供直接答案)。
如前所述,使用 Python 3.5+,很容易:
import glob
for f in glob.glob('d:/temp/**/*', recursive=True):
print(f)
#d:\temp\New folder
#d:\temp\New Text Document - Copy.txt
#d:\temp\New folder\New Text Document - Copy.txt
#d:\temp\New folder\New Text Document.txt
from pathlib import Path
for f in Path('d:/temp').glob('**/*'):
print(f)
os.scandir
是glob
在内部做什么。所以这里是如何直接做到这一点,使用yield
:
def listpath(path):
for f in os.scandir(path):
f2 = os.path.join(path, f)
if os.path.isdir(f):
yield f2
yield from listpath(f2)
else:
yield f2
for f in listpath('d:\\temp'):
print(f)
正如 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
我们能够对指定父目录下的所有文件进行一次扫描,将它们的名称保存到一个列表中(超过一百万个文件),然后使用该列表来确定我们需要随时打开哪些文件仅基于文件命名约定与它们所在的文件夹指向未来。
您可以使用该函数glob.glob()
或glob.iglob()
直接从 glob 模块从目录/文件和子目录/子文件中递归检索路径。
句法:
glob.glob(pathname, *, recursive=False) # pathname = '/path/to/the/directory' or subdirectory
glob.iglob(pathname, *, recursive=False)
在您的示例中,可以这样写:
import glob
import os
configfiles = [f for f in glob.glob("C:/Users/sam/Desktop/*.txt")]
for f in configfiles:
print(f'Filename with path: {f}')
print(f'Only filename: {os.path.basename(f)}')
print(f'Filename without extensions: {os.path.splitext(os.path.basename(f))[0]}')
输出:
Filename with path: C:/Users/sam/Desktop/test_file.txt
Only filename: test_file.txt
Filename without extensions: test_file