删除与模式匹配的多个文件

时间:2009-10-10 18:32:44

标签: python

我使用Python和Django建立了一个在线画廊。我刚开始添加编辑功能,从旋转开始。我使用sorl.thumbnail按需自动生成缩略图。

当我编辑原始文件时,我需要清理所有缩略图,以便生成新的缩略图。每张图片中有三个或四个(我在不同场合有不同的图像)。

可以在文件变量中进行硬编码...但是这很麻烦,如果我改变了我的工作方式,我需要重新访问代码。

理想情况下,我想要进行正则表达式删除。在正则表达式术语中,我的所有原件都是这样命名的:

^(?P<photo_id>\d+)\.jpg$

所以我想删除:

^(?P<photo_id>\d+)[^\d].*jpg$

(我用我要清理的ID替换photo_id。)

9 个答案:

答案 0 :(得分:66)

glob方法的变体,适用于Python 3:

import glob, os
for f in glob.glob("P*.jpg"):
    os.remove(f)

编辑:在Python 3.4+中,您可能希望使用pathlib:

from pathlib import Path
for p in Path(".").glob("P*.jpg"):
    p.unlink()

答案 1 :(得分:56)

尝试这样的事情:

import os, re

def purge(dir, pattern):
    for f in os.listdir(dir):
        if re.search(pattern, f):
            os.remove(os.path.join(dir, f))

然后你将传递包含文件和你想要匹配的模式的目录。

答案 2 :(得分:11)

如果需要递归到多个子目录,可以使用此方法:

import os, re, os.path
pattern = "^(?P<photo_id>\d+)[^\d].*jpg$"
mypath = "Photos"
for root, dirs, files in os.walk(mypath):
    for file in filter(lambda x: re.match(pattern, x), files):
        os.remove(os.path.join(root, file))

您可以安全地从dirs中删除子目录,其中包含要在每个节点访问的子目录列表。

请注意,如果您在目录中,还可以使用glob.glob(pattern)获取与简单模式表达式相对应的文件。在这种情况下,您必须减去文件集以保留整个集合,因此上面的代码更有效。

答案 3 :(得分:8)

这个怎么样?

import glob, os, multiprocessing
p = multiprocessing.Pool(4)
p.map(os.remove, glob.glob("P*.jpg"))

请注意,这不会进行递归并使用通配符(而不是正则表达式)。

<强>更新 在Python 3中,map()函数将返回迭代器,而不是列表。这很有用,因为您可能希望对项目进行某种处理,并且迭代器总是会为此节省更多内存。

但是,如果列表是真正所需要的,请执行以下操作:

...
list(p.map(os.remove, glob.glob("P*.jpg")))

我同意这不是最有效的方式,但它很简洁并且能够胜任。

答案 4 :(得分:2)

我不清楚你真的想要进行任何命名组匹配 - 在你描述的用途中,photoid是删除函数的输入,命名组的目的是“输出”,即从匹配的字符串中提取某些子字符串(并在匹配对象中按名称访问它们)。所以,我建议采用一种更简单的方法:

import re
import os

def delete_thumbnails(photoid, photodirroot):
  matcher = re.compile(r'^%s\d+\D.*jpg$' % photoid)
  numdeleted = 0
  for rootdir, subdirs, filenames in os.walk(photodirroot):
    for name in filenames:
      if not matcher.match(name):
        continue
      path = os.path.join(rootdir, name)
      os.remove(path)
      numdeleted += 1
  return "Deleted %d thumbnails for %r" % (numdeleted, photoid)

如果您需要一次删除多个匹配的ID(例如,r'abc[def]以在一次调用中删除abcd,abce和abcf),您可以将photoid作为普通字符串传递,或者作为RE模式传递 - 这就是我将它插入RE模式中的原因,而不是像通常的做法那样插入字符串re.escape(photoid)。某些部分,例如计算删除次数和最后返回信息性消息,显然是你应该删除的褶边,如果它们在你的用例中没有给你增加价值。

其他人,例如“if not ... // continue”模式,在Python中是强烈推荐的做法(平坦优于嵌套:一旦确定没有任何内容,就会挽救循环的下一个循环要做到这一点比在if内嵌套要完成的操作更好,尽管当然其他代码的安排也会起作用。

答案 5 :(得分:2)

我的推荐:

def purge(dir, pattern, inclusive=True):
    regexObj = re.compile(pattern)
    for root, dirs, files in os.walk(dir, topdown=False):
        for name in files:
            path = os.path.join(root, name)
            if bool(regexObj.search(path)) == bool(inclusive):
                os.remove(path)
        for name in dirs:
            path = os.path.join(root, name)
            if len(os.listdir(path)) == 0:
                os.rmdir(path)

默认情况下,这将递归删除与模式匹配的每个文件,如果包含,则每个文件都不为true。然后它将从目录树中删除任何空文件夹。

答案 6 :(得分:1)

import os, sys, glob, re

def main():

    mypath = "<Path to Root Folder to work within>"
    for root, dirs, files in os.walk(mypath):
        for file in files:
            p = os.path.join(root, file)
            if os.path.isfile(p):
                if p[-4:] == ".jpg": #Or any pattern you want
                os.remove(p)

答案 7 :(得分:0)

我发现Popen(["rm " + file_name + "*.ext"], shell=True, stdout=PIPE).communicate()是解决此问题的更简单方法。虽然这很容易受到注入攻击,但如果您的程序在内部使用它,我不会发现任何问题。

答案 8 :(得分:0)

5.1