获取目录中已过滤的文件列表

mho*_*ost 254 python filesystems glob wildcard directory-listing

我试图使用Python获取目录中的文件列表,但我不想要所有文件的列表.

我本质上想要的是能够做类似下面的事情,但使用Python而不是执行ls.

ls 145592*.jpg
Run Code Online (Sandbox Code Playgroud)

如果没有内置的方法,我目前正在考虑编写一个for循环来迭代结果os.listdir()并将所有匹配的文件附加到一个新列表.

但是,也有很多的文件在该目录中,所以我希望有一个更有效的方法(或内置的方法).

Ign*_*ams 350

glob.glob('145592*.jpg')

  • 哦,我只是注意到Python文档说glob()"是通过使用os.listdir()和fnmatch.fnmatch()函数完成的,而不是实际调用子shell".换句话说,glob()没有人们可能期望的效率改进. (18认同)
  • @Ben为什么调用子shell(子进程)会有任何效率提升? (7认同)
  • @PauloNeves:是的,我上面的评论在7年后对我来说也没有意义.:-)我猜我指的是`glob()`只使用listdir + fnmatch,而不是特殊的操作系统调用来进行通配符过滤.例如,在Windows上,`FindFirstFile` API允许您指定通配符,以便操作系统直接进行过滤,并且可能更有效(我不认为在Linux上有等效的). (5认同)
  • 有一个主要区别:`glob.glob('145592*.jpg')`打印文件的整个绝对路径,而`ls 145592*.jpg`只打印文件列表. (4认同)
  • 你在哪里指定目录? (3认同)
  • 这个搜索什么目录? (2认同)
  • 不要忘记使用“导入 glob” (2认同)

Ben*_*oyt 114

glob.glob()绝对是这样做的方式(根据Ignacio).但是,如果你确实需要更复杂的匹配,你可以使用列表理解来完成它re.match(),如下所示:

files = [f for f in os.listdir('.') if re.match(r'[0-9]+.*\.jpg', f)]
Run Code Online (Sandbox Code Playgroud)

更灵活,但正如您所说,效率较低.

  • 是的,肯定更强大 - 但fnmatch确实支持`[0123456789]`序列([见文档](http://docs.python.org/2/library/fnmatch.html)),它也有`fnmatch .filter()`函数使得这个循环更有效率. (3认同)

ram*_*ey0 43

把事情简单化:

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)]
Run Code Online (Sandbox Code Playgroud)

我更喜欢这种列表推导形式,因为它读得很好.

我读了第四行:对于我的路径的os.listdir中的每个fn,只给我匹配任何一个包含的扩展名.

新手python程序员可能很难真正习惯使用列表推导进行过滤,并且它可能会为非常大的数据集带来一些内存开销,但是为了列出目录和其他简单的字符串过滤任务,列表推导会导致更干净可记录的代码.

这个设计的唯一之处在于它不能保护你免于犯错传递字符串而不是列表.例如,如果您不小心将字符串转换为列表并最终检查字符串的所有字符,您最终可能会得到一大堆误报.

但是,与一个难以理解的解决方案相比,最好有一个容易解决的问题.

  • 并不是说在这里需​​要`any()`,因为`str.endswith()`需要一个*序列*的结尾.`如果fn.endswith(included_extentensions)`绰绰有余. (5认同)
  • 除了不使用Martijn指出的`str.endswith(seq)`的效率低下,这是不正确的,因为文件必须以`.ext`结尾才能拥有该扩展名.此代码还将查找(例如)名为"myjpg"的文件或名为"png"的目录.要修复,只需在`included_extensions`中为每个扩展名添加前缀`.`. (3认同)
  • 我总是对答案中显然尚未运行或无法运行的代码有点警惕。变量“included_extensions”与“included_extensions”?遗憾的是,否则这是我的首选答案。 (2认同)

Ris*_*nha 35

另外一个选项:

>>> import os, fnmatch
>>> fnmatch.filter(os.listdir('.'), '*.py')
['manage.py']
Run Code Online (Sandbox Code Playgroud)

https://docs.python.org/3/library/fnmatch.html

  • 这正是`glob`在单行上的作用. (4认同)
  • 唯一的区别是“glob”返回完整路径,而不是“os.listdir”仅返回文件名。至少 Python 2 中是这样的。 (2认同)

Vla*_*den 12

您可以使用Python 标准库 3.4 及更高版本中提供的pathlib 。

from pathlib import Path

files = [f for f in Path.cwd().iterdir() if f.match("145592*.jpg")]
Run Code Online (Sandbox Code Playgroud)

  • 或者,只需使用 `Path.cwd().glob("145592*.jpg")`...无论如何,这绝对应该在此页面上更高。`pathlib` 是正确的选择 (3认同)

PAD*_*MKO 10

初步代码

import glob
import fnmatch
import pathlib
import os

pattern = '*.py'
path = '.'
Run Code Online (Sandbox Code Playgroud)

解决方案1 - 使用"glob"

# lookup in current dir
glob.glob(pattern)

In [2]: glob.glob(pattern)
Out[2]: ['wsgi.py', 'manage.py', 'tasks.py']
Run Code Online (Sandbox Code Playgroud)

解决方案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']
Run Code Online (Sandbox Code Playgroud)

变体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))
Run Code Online (Sandbox Code Playgroud)

结果

./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
Run Code Online (Sandbox Code Playgroud)

解决方案3 - 使用"pathlib"

# lookup in current dir
path_ = pathlib.Path('.')
tuple(path_.glob(pattern))

# lookup recursive
tuple(path_.rglob(pattern))
Run Code Online (Sandbox Code Playgroud)

笔记:

  1. 在Python 3.4上测试过
  2. 模块"pathlib"仅在Python 3.4中添加
  3. Python 3.5添加了一个使用glob.glob https://docs.python.org/3.5/library/glob.html#glob.glob进行递归查找的功能 .由于我的机器安装了Python 3.4,我还没有测试过.


gho*_*g74 9

使用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)
Run Code Online (Sandbox Code Playgroud)


pin*_*ash 8

过滤glob模块:

导入球

import glob
Run Code Online (Sandbox Code Playgroud)

通配符:

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']
Run Code Online (Sandbox Code Playgroud)

接头扩展.txt

files = glob.glob("/home/ach/*/*.txt")
Run Code Online (Sandbox Code Playgroud)

一个字符

glob.glob("/home/ach/file?.txt")
Run Code Online (Sandbox Code Playgroud)

编号范围

glob.glob("/home/ach/*[0-9]*")
Run Code Online (Sandbox Code Playgroud)

字母范围

glob.glob("/home/ach/[a-c]*")
Run Code Online (Sandbox Code Playgroud)


Evg*_*M86 5

import os

dir="/path/to/dir"
[x[0]+"/"+f for x in os.walk(dir) for f in x[2] if f.endswith(".jpg")]
Run Code Online (Sandbox Code Playgroud)

这将为您提供带有完整路径的 jpg 文件列表。您可以替换x[0]+"/"+ff的只是文件名。您还可以替换f.endswith(".jpg")为您希望的任何字符串条件。