我正在尝试使用 Python 获取目录中的文件列表,但我不想要所有文件的列表。
我本质上想要的是能够执行以下操作,但使用 Python 而不是执行 ls。
ls 145592*.jpg
如果没有内置方法,我目前正在考虑编写一个 for 循环来遍历 os.listdir()
的结果并将所有匹配的文件附加到一个新列表中。
但是,该目录中有很多文件,因此我希望有一种更有效的方法(或内置方法)。
glob.glob()
绝对是这样做的方法(根据 Ignacio)。但是,如果您确实需要更复杂的匹配,您可以使用列表推导和 re.match()
来完成,如下所示:
files = [f for f in os.listdir('.') if re.match(r'[0-9]+.*\.jpg', f)]
更灵活,但正如您所指出的,效率较低。
[0-9]+
之类的操作
把事情简单化:
import os
relevant_path = "[path to folder]"
included_extensions = ['jpg','jpeg', 'bmp', 'png', 'gif']
file_names = [fn for fn in os.listdir(relevant_path)
if any(fn.endswith(ext) for ext in included_extensions)]
我更喜欢这种形式的列表理解,因为它的英文读起来很好。
我将第四行读为:对于我的路径的 os.listdir 中的每个 fn,只给我与我包含的任何一个扩展匹配的那些。
新手 python 程序员可能很难真正习惯使用列表推导进行过滤,并且对于非常大的数据集可能会有一些内存开销,但是对于列出目录和其他简单的字符串过滤任务,列表推导会导致更干净可记录的代码。
这种设计唯一的一点是它不能保护你避免犯下传递字符串而不是列表的错误。例如,如果您不小心将字符串转换为列表并最终检查字符串的所有字符,您最终可能会得到大量误报。
但最好有一个容易解决的问题,而不是一个难以理解的解决方案。
any()
,因为 str.endswith()
采用 sequence 结尾。 if fn.endswith(included_extentensions)
绰绰有余。
str.endswith(seq)
的低效率之外,这是不正确的,因为文件必须以 .ext
结尾才能具有该扩展名。此代码还将找到(例如)名为“myjpg”的文件或仅名为“png”的目录。要解决此问题,只需在 included_extensions
中为每个扩展添加前缀 .
。
included_extensions
与 included_extentsions
?可惜,否则这是我的首选答案。
另外的选择:
>>> import os, fnmatch
>>> fnmatch.filter(os.listdir('.'), '*.py')
['manage.py']
https://docs.python.org/3/library/fnmatch.html
glob
在一行中所做的。
glob
返回完整路径,而 os.listdir
只返回文件名。至少这是 Python 2 中正在发生的事情。
fnmatch
和 os
并且不想导入另一个模块的人,即。 glob
。
使用 glob 模块过滤:
导入全局
import glob
外卡:
files=glob.glob("data/*")
print(files)
Out:
['data/ks_10000_0', 'data/ks_1000_0', 'data/ks_100_0', 'data/ks_100_1',
'data/ks_100_2', 'data/ks_106_0', 'data/ks_19_0', 'data/ks_200_0', 'data/ks_200_1',
'data/ks_300_0', 'data/ks_30_0', 'data/ks_400_0', 'data/ks_40_0', 'data/ks_45_0',
'data/ks_4_0', 'data/ks_500_0', 'data/ks_50_0', 'data/ks_50_1', 'data/ks_60_0',
'data/ks_82_0', 'data/ks_lecture_dp_1', 'data/ks_lecture_dp_2']
过滤器扩展名 .txt:
files = glob.glob("/home/ach/*/*.txt")
单个字符
glob.glob("/home/ach/file?.txt")
数字范围
glob.glob("/home/ach/*[0-9]*")
字母范围
glob.glob("/home/ach/[a-c]*")
初步代码
import glob
import fnmatch
import pathlib
import os
pattern = '*.py'
path = '.'
解决方案 1 - 使用“glob”
# lookup in current dir
glob.glob(pattern)
In [2]: glob.glob(pattern)
Out[2]: ['wsgi.py', 'manage.py', 'tasks.py']
解决方案 2 - 使用“os”+“fnmatch”
变体 2.1 - 在当前目录中查找
# lookup in current dir
fnmatch.filter(os.listdir(path), pattern)
In [3]: fnmatch.filter(os.listdir(path), pattern)
Out[3]: ['wsgi.py', 'manage.py', 'tasks.py']
变体 2.2 - 递归查找
# lookup recursive
for dirpath, dirnames, filenames in os.walk(path):
if not filenames:
continue
pythonic_files = fnmatch.filter(filenames, pattern)
if pythonic_files:
for file in pythonic_files:
print('{}/{}'.format(dirpath, file))
结果
./wsgi.py
./manage.py
./tasks.py
./temp/temp.py
./apps/diaries/urls.py
./apps/diaries/signals.py
./apps/diaries/actions.py
./apps/diaries/querysets.py
./apps/library/tests/test_forms.py
./apps/library/migrations/0001_initial.py
./apps/polls/views.py
./apps/polls/formsets.py
./apps/polls/reports.py
./apps/polls/admin.py
解决方案 3 - 使用“pathlib”
# lookup in current dir
path_ = pathlib.Path('.')
tuple(path_.glob(pattern))
# lookup recursive
tuple(path_.rglob(pattern))
笔记:
在 Python 3.4 上测试 仅在 Python 3.4 中添加了模块“pathlib” Python 3.5 添加了一个用于使用 glob.glob https://docs.python.org/3.5/library/glob.html#glob 进行递归查找的功能。全球。由于我的机器安装了 Python 3.4,所以我没有测试过。
使用 os.walk 递归地列出你的文件
import os
root = "/home"
pattern = "145992"
alist_filter = ['jpg','bmp','png','gif']
path=os.path.join(root,"mydir_to_scan")
for r,d,f in os.walk(path):
for file in f:
if file[-3:] in alist_filter and pattern in file:
print os.path.join(root,file)
file.endswith(alist_filter)
就足够了。
any(file.endswith(filter) for filter in alist_filter)
作为 endswith()
不允许列表作为参数。
您可以使用 Python 标准库 3.4 及更高版本中提供的 pathlib。
from pathlib import Path
files = [f for f in Path.cwd().iterdir() if f.match("145592*.jpg")]
Path.cwd().glob("145592*.jpg")
...无论如何,这在此页面上肯定应该更高。 pathlib
是要走的路
import os
dir="/path/to/dir"
[x[0]+"/"+f for x in os.walk(dir) for f in x[2] if f.endswith(".jpg")]
这将为您提供包含完整路径的 jpg 文件列表。对于文件名,您可以将 x[0]+"/"+f
替换为 f
。您还可以将 f.endswith(".jpg")
替换为您希望的任何字符串条件。
您可能还喜欢更高级的方法(我已经实现并打包为 findtools):
from findtools.find_files import (find_files, Match)
# Recursively find all *.txt files in **/home/**
txt_files_pattern = Match(filetype='f', name='*.txt')
found_files = find_files(path='/home', match=txt_files_pattern)
for found_file in found_files:
print found_file
可以安装
pip install findtools
“path/to/images”中带有“jpg”和“png”扩展名的文件名:
import os
accepted_extensions = ["jpg", "png"]
filenames = [fn for fn in os.listdir("path/to/images") if fn.split(".")[-1] in accepted_extensions]
您可以定义模式并检查它。在这里,我采用了开始和结束模式并在文件名中查找它们。 FILES 包含目录中所有文件的列表。
import os
PATTERN_START = "145592"
PATTERN_END = ".jpg"
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
for r,d,FILES in os.walk(CURRENT_DIR):
for FILE in FILES:
if PATTERN_START in FILE.startwith(PATTERN_START) and PATTERN_END in FILE.endswith(PATTERN_END):
print FILE
PATTERN_START
应用作 FILE.startwith(PATTERN_START)
,而 PATTERN_END
应用作 FILE.endswith(PATTERN_END)
以避免任何其他文件名组合。例如上面的代码也将允许 jpg_sample_145592
文件。这是不正确的。
if FILE.startwith(PATTERN_START) and FILE.endswith(PATTERN_END):
import re
import os
dir_name = "."
files = [os.path.join(dir_name, f) for f in os.listdir(dir_name) if re.match(r'.*\.(jpg|jpeg|png)', f)]
您可以使用 subprocess.check_ouput() 作为
import subprocess
list_files = subprocess.check_output("ls 145992*.jpg", shell=True)
当然,引号之间的字符串可以是您想在 shell 中执行的任何内容,并存储输出。
ls
's output should not be parsed。
不定期副业成功案例分享
glob.glob('145592*.jpg')
打印文件的整个绝对路径,而ls 145592*.jpg
仅打印文件列表。glob()
只使用 listdir+fnmatch,而不是特殊的操作系统调用来进行通配符过滤。例如,在 Windows 上,FindFirstFile
API 允许您指定通配符,以便操作系统直接进行过滤,并且可能更有效(我认为 Linux 上没有等效项)。import glob