Удаление нескольких файлов, соответствующих шаблону
Я сделал онлайн-галерею, используя Python и Django. Я только начал добавлять функции редактирования, начиная с вращения. Я использую sorl.thumbnail для автоматического создания эскизов по запросу.
Когда я редактирую исходный файл, мне нужно очистить все миниатюры, чтобы они генерировались. Есть три или четыре из них на изображение (у меня разные для разных случаев).
Я мог бы жестко закодировать в переменных файлах... Но это беспорядочно, и если я изменю способ, которым я что-то делаю, мне нужно будет пересмотреть код.
В идеале я хотел бы сделать regex-delete. В терминах регулярных выражений все мои оригиналы называются так:
^(?P<photo_id>\d+)\.jpg$
Итак, я хочу удалить:
^(?P<photo_id>\d+)[^\d].*jpg$
(Где я заменяю photo_id
идентификатором, который хочу очистить.)
Ответы
Ответ 1
Попробуйте что-то вроде этого:
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
Вариант подхода 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()
Ответ 3
Если вам нужна рекурсия в несколько подкаталогов, вы можете использовать этот метод:
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
, который содержит список подкаталогов для посещения на каждом node.
Обратите внимание, что если вы находитесь в каталоге, вы также можете получить файлы, соответствующие простому выражению шаблона, с помощью glob.glob(pattern)
. В этом случае вам придется вычесть набор файлов для хранения всего набора, поэтому приведенный выше код более эффективен.
Ответ 4
Как насчет этого?
import glob, os, multiprocessing
p = multiprocessing.Pool(4)
p.map(os.remove, glob.glob("P*.jpg"))
Помните, что это не делает рекурсии и использует подстановочные знаки (не регулярное выражение).
Ответ 5
Мне непонятно, что вы действительно хотите выполнить любое сопоставление именованной группы - при использовании, которое вы описываете, фотоид является входом в функцию удаления, а назначение названных групп - "вывод", т.е. извлечение определенные подстроки из согласованной строки (и доступ к ним по имени в объекте совпадения). Поэтому я бы рекомендовал более простой подход:
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)
Вы можете передать фотоид как обычную строку или как часть образца RE, если вам нужно удалить сразу несколько подходящих идентификаторов (например, r'abc[def]
, чтобы удалить abcd, abce и abcf за один вызов) - что причина, по которой я вставляю его буквально в шаблон RE, вместо того, чтобы вставлять строку re.escape(photoid)
, как это было бы обычной практикой. Некоторые части, такие как подсчет количества удалений и возвращение информационного сообщения в конце, являются, очевидно, излишествами, которые вы должны удалить, если они не дают вам никакой добавленной стоимости в вашем прецеденте.
Другие, такие как шаблон "if not...//continue", рекомендуются в Python (плоская лучше, чем вложенная: выпрыгивая на следующую ногу цикла, как только вы определяете, нет ничего сделать это лучше, чем вложенные действия, выполняемые в if
), хотя, конечно, будут работать и другие механизмы кода.
Ответ 6
Мое одобрение:
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)
Это будет рекурсивно удалять каждый файл, который соответствует шаблону по умолчанию, и каждый файл, который не имеет, если включен, является истинным. Затем он удалит все пустые папки из дерева каталогов.
Ответ 7
Я нахожу Popen(["rm " + file_name + "*.ext"], shell=True, stdout=PIPE).communicate()
более простым решением этой проблемы. Хотя это подвержено атакам с инъекциями, я не вижу никаких проблем, если ваша программа использует это внутри.
Ответ 8
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))