2009-10-10 9 views
36

Zrobiłem galerię online używając Pythona i Django. Właśnie zacząłem dodawać funkcje edycji, zaczynając od obrotu. Używam sorl.thumbnail do automatycznego generowania miniatur na żądanie.Usuwanie wielu plików pasujących do wzorca

Kiedy edytuję oryginalny plik, muszę wyczyścić wszystkie miniatury, aby wygenerować nowe. Na obrazie są trzy lub cztery (mam różne na różne okazje).

I może być twardy kod w plikach-odmianach ... Ale to jest brudne i jeśli zmienię sposób, w jaki robię rzeczy, będę musiał ponownie przejrzeć kod.

Idealnie chciałabym zrobić regex-usunąć. Pod względem regex, wszystkie moje oryginały są nazwane tak:

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

Więc chcę usunąć: (. Gdzie mogę wymienić photo_id z identyfikatorem Chcę oczyścić)

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

Odpowiedz

37

Wypróbuj coś takiego:

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

Następnie należy przekazać katalog zawierający pliki i wzór, który chcesz dopasować.

+7

I Kusiło by, by skompilować regex przed wejściem w pętlę ... Ale tak, to wygląda dobrze. – Oli

+1

można zamiast tego użyć 'glob.glob'. – pylover

+0

Piękna funkcja. Dziękujemy – ChickenFeet

8

Jeśli potrzebujesz rekursji na kilka podkatalogów, można użyć tej metody:

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

Można bezpiecznie usunąć podkatalogi na bieżąco z dirs, który zawiera listę podkatalogów do odwiedzenia w każdym węźle.

Należy pamiętać, że jeśli jesteś w katalogu, można również uzyskać pliki odpowiadające prostego wzoru ekspresji z glob.glob(pattern). W takim przypadku będziesz musiał odjąć zbiór plików, aby trzymać się z dala od całego zestawu, więc powyższy kod jest bardziej wydajny.

2

Nie jest dla mnie jasne, czy faktycznie chcesz wykonać dopasowanie nazwanych grup - w opisanym przez ciebie użyciu zdjęciem jest wejście do funkcji usuwania, a nazwane grupy mają "wynik", tj. wyodrębnianie pewnych podłańcuchów z dopasowanego ciągu (i uzyskiwanie dostępu do nich po nazwie w obiekcie dopasowania). Tak, polecam prostsze podejście:

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) 

możesz przekazać photoID jako zwykłego łańcucha, albo jako element RE wzór, jeśli trzeba usunąć kilka dopasowywalny identyfikatorów naraz (np r'abc[def] usunąć ABCD abce i abcf w jednym wywołaniu) - to jest powód, dla którego wstawiam go dosłownie we wzorze RE, zamiast wstawiania ciągu re.escape(photoid), co byłoby normalną praktyką. Niektóre części, takie jak zliczanie liczby skasowanych i zwracanie na końcu wiadomości informacyjnej, są oczywiście dodatkami, które należy usunąć, jeśli nie dają żadnej wartości dodanej w przypadku użycia.

Inne, takie jak wzór "jeśli nie ... // kontynuuj", są wysoce polecaną praktyką w Pythonie (płaska jest lepsza niż zagnieżdżona: przechodzenie do następnego etapu pętli, gdy tylko stwierdzisz, że istnieje nic na ten temat nie jest lepsze niż zagnieżdżanie czynności do wykonania w ramach if), chociaż oczywiście inne układy kodu też by działały.

2

Moja poleca:

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) 

To będzie rekursywnie usunąć każdy plik, który pasuje do wzorca domyślnie i każdy plik, który nie jest prawdą, jeśli włącznie. Następnie usunie wszystkie puste foldery z drzewa katalogów.

+0

Proszę poprawić opis "inclusive". Lepiej też nie dopasować całej ścieżki do wzorca, ale tylko do nazwy pliku, ponieważ gdy wzorzec znajduje się w innym miejscu ścieżki, przypadkowo usuniesz wszystko. Pomocna byłaby również uwaga, że ​​język wzorca jest językiem 're', a nie np. 'bash'. Zasugeruję odpowiednią zmianę. To jest kwestia gustu, jeśli usuniesz puste katalogi w ten sposób, ponieważ spowoduje to również usunięcie pustych katalogów, które były puste, nawet przed wzorcem 'rm', tj. Zwykle niezamierzonymi usunięciami. – flaschbier

0

Uważam, że Popen(["rm " + file_name + "*.ext"], shell=True, stdout=PIPE).communicate() jest znacznie prostszym rozwiązaniem tego problemu. Chociaż jest to podatne na ataki przy wtrysku, nie widzę żadnych problemów, jeśli twój program używa tego wewnętrznie.

7

Co powiesz na to?

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

Pamiętaj, że to nie robi rekurencji i używa symboli wieloznacznych (nie wyrażeń regularnych).

+1

map() ma na celu transformację zestawu wartości, zamiast uruchamiać na nich dowolne polecenie. Dlatego nie jest to najbardziej zalecana technika, a właściwie kończy się niepowodzeniem w Pythonie 3, ponieważ map() zwraca teraz wartość iterowalną, zamiast natychmiastowej oceny funkcji. –

+2

Należy zwrócić uwagę, że mapa zwraca generator z python 3, a to * nie * wykona funkcję remove. –

31

wariacja na temat podejścia glob, że będzie pracować z Python 3:

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

Edit W Pythonie 3.4+ możesz użyć pathlib:

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

os.remove daje mi błąd systemu (Windows), więc użyłem zamiast tego shutil.rmtree. – sparrow

+0

@sparrow Pytanie brzmiało, jak usunąć * pliki * pasujące do wzorca, a nie usunąć całe drzewa katalogów pasujące do wzorca. –

+0

Zmień glob.glob ("P * .jpg") -> glob ("P * .jpg") – Patricio

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

Podczas gdy ten kod może rozwiązać pytanie, [w tym wyjaśnienie] (// meta.stackexchange.com/questions/114762/explaining-entirely-code-ans -answers), jak i dlaczego to rozwiązuje problem, mogłoby naprawdę pomóc w ulepszeniu jakość Twojego postu i prawdopodobnie zwiększy liczbę głosów up. Pamiętaj, że odpowiadasz na pytanie dla czytelników w przyszłości, a nie tylko pytasz teraz. Zmodyfikuj swoją odpowiedź, aby dodać wyjaśnienie i podaj, jakie ograniczenia i założenia mają zastosowanie. – Makyen

Powiązane problemy