删除多个匹配模式的文件


68

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

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

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

理想情况下,我想进行正则删除。用正则表达式来说,我所有的原件都这样命名:

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

所以我想删除:

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

(在我photo_id要清洁的ID替换的地方。)

Answers:


64

尝试这样的事情:

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))

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


8
在进入循环之前,我很想先编译正则表达式。但是,看起来不错。
— 奥利

1
可以使用它glob.glob代替它。
— pylover '16

92

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()

2
os.remove给了我系统错误(Windows),所以我改用shutil.rmtree。
— 麻雀

1
@sparrow问题是如何删除与模式匹配的文件,而不是删除与模式匹配的整个目录树。
— 山姆公牛

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)。在这种情况下,您将不得不从整个文件集中减去文件集,因此上面的代码效率更高。


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
map()用于转换一组值,而不是对它们运行任意命令。因此,这不是最推荐的技术,并且实际上在Python 3中失败,因为map()现在返回一个可迭代的函数,而不是立即评估函数。
— 山姆公牛

2
请注意,地图会返回自python 3起的生成器,这不会执行remove函数。
— Ivaylo Strandjev,2016年

2

我不清楚您实际上是否要进行任何命名组匹配-在您描述的用途中,photoid是删除功能的输入,命名组的目的是“输出”,即从中提取某些子字符串匹配的字符串(并在match对象中按名称访问它们)。因此,我建议一种更简单的方法:

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)

您可以将photoid作为普通字符串传递,也可以作为RE模式传递,如果您需要一次删除多个可匹配的ID(例如,在一次r'abc[def]调用中删除abcd,abce和abcf),这就是我从字面上将其插入RE模式,而不是插入字符串re.escape(photoid)像通常那样。某些部分(例如计算删除次数和最后返回信息性消息)显然是多余的,如果在用例中没有任何附加价值,则应删除这些部分。

强烈建议在Python中采用其他方式,例如“ if not ... // Continue”模式(扁平比嵌套好):一旦确定无事可做,就循环到循环的下一段这比嵌套要在if)中完成的操作要好,尽管代码的其他安排当然也可以工作。


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,则不删除每个文件。然后,它将从目录树中删除所有空文件夹。


请更正的描述inclusive。我也最好不要将整个路径与模式匹配,而只与文件名匹配,因为当模式位于路径中的其他位置时,您将无意中删除所有内容。另外,如果模式语言是re而不是例如,将很有帮助bash。我将建议进行相应的编辑。如果您以这种方式删除空目录,这是一个好习惯,因为它还会删除甚至在模式之前就已经为空的空目录rm,即通常是无意删除。
— flaschbier 2015年

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)

0

我发现Popen(["rm " + file_name + "*.ext"], shell=True, stdout=PIPE).communicate()这是解决此问题的简单得多的解决方案。尽管这很容易造成注入攻击,但是如果您的程序在内部使用此功能,我看不到任何问题。


0
def recursive_purge(dir, pattern):
    for f in os.listdir(dir):
        if os.path.isdir(os.path.join(dir, f)):
            recursive_purge(os.path.join(dir, f), pattern)
        elif re.search(pattern, os.path.join(dir, f)):
            os.remove(os.path.join(dir, f))

1
尽管这段代码可以解决问题,但包括解释如何以及为什么解决该问题的说明,确实可以帮助提高您的帖子质量,并可能导致更多的投票。请记住,您将来会为读者回答问题,而不仅仅是现在问的人。请编辑您的答案以添加解释,并指出适用的限制和假设。
— Makyen
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.