2009-10-10 21 views
36

Python ve Django kullanarak çevrimiçi bir galeri hazırladım. Döndürme ile başlayan düzenleme işlevlerini yeni eklemeye başladım. İsteğe bağlı olarak küçük resimleri otomatik oluşturmak için sorl.thumbnail kullanıyorum.Bir desenle eşleşen birden fazla dosyayı silme

Özgün dosyayı düzenlediğimde, yeni küçük resimlerin oluşturulmasını sağlamak için tüm küçük resimleri temizlemem gerekiyor. Görüntü başına üç veya dördü vardır (farklı durumlar için farklı olanlarım var).

Ben olabilir dosya varients içinde gömmemeli ... Ama bu dağınık ve ben şeyler biçimini değiştirmek, ben kod tekrar gerekecektir.

İdeal olarak regex-delete yapmak istiyorum. regex açısından, tüm orijinalleri şöyle adlandırılır:

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

yüzden silmek istiyorum: (. Ben temizlemek istiyorum kimliğiyle photo_id yerine)

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

cevap

37

Şunun gibi bir şey deneyin:

Daha sonra dosyaları içeren dizini geçirirsiniz ve eşleştirmek istediğiniz desen. Güvenle her düğüm noktasında ziyaret etmek alt dizin listesini içeren dirs gelen anında alt dizinleri kaldırabilir

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

:

+7

I: Eğer pathlib kullanmak isteyebilirsiniz 3.4+ Python Döngüye girmeden önce regex'i derlemek için cazip olmalı ... Ama evet, bu iyi görünüyor. – Oli

+1

, bunun yerine glob.glob' işlevini kullanmakta sorun yoktur. – pylover

+0

Güzel işlev. Teşekkürler – ChickenFeet

8

birkaç alt dizinleri içine özyinelemeye gerekiyorsa, bu yöntemi kullanabilirsiniz.

Bir dizinde iseniz, glob.glob(pattern) ile basit bir desen ifadesine karşılık gelen dosyaları da alabilirsiniz. Bu durumda, tüm kümeden saklanacak dosya kümesini çıkarmanız gerekir, bu nedenle yukarıdaki kod daha verimli olur.

2

Aslında adlandırılmış grup eşleştirmesi yapmak istediğiniz açık değil - tanımladığınız kullanımda, photoid silme işlevine bir girdi ve adlandırılmış grupların amacı "çıktı" olur, Örneğin, belirli alt dizeleri eşleşen dizeden ayıklamak (ve eşleme nesnesinde adlarına göre erişerek). Yani, daha basit bir yaklaşım öneriyoruz: Aynı anda birkaç matchable kimliklerini kaldırmanız gerekiyorsa normal dize olarak PHOTOID geçmesi veya RE desen parça olarak yapabilirsiniz

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) 

(örneğin r'abc[def] abcd kaldırmak için, abce ve abcf tek bir aramada) - bu, normal uygulamada olduğu gibi re.escape(photoid) dizgesini eklemek yerine, RE modelinde tam anlamıyla eklememden kaynaklanır. Silme sayısının sayılması ve bilgilendirici bir mesajın geri verilmesi gibi belirli kısımlar, kullanım durumunuzda size herhangi bir katma değer vermezlerse kaldırmanız gereken açık bir fırfırdır.

"If not ... // continue" deseni gibi diğerleri, Python'da çok tavsiye edilir (düz yuvadan daha iyidir: orada olduğunu belirledikten sonra döngünün bir sonraki ayağına çıkmak kodun diğer düzenlemelerinin de işe yaramasına rağmen, bu konuda yapılacak hiçbir şey, if içinde yapılacak eylemleri yerleştirmekten daha iyidir.

2

Benim recomendation:

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) 

Bu yinelemeli varsayılan olarak kalıpla eşleşen her dosyayı ve kapsayıcı doğruysa değil her dosyayı kaldıracaktır. Daha sonra boş klasörleri dizin ağacından kaldıracaktır.

+0

Lütfen "inclusive" için tanımı düzeltin. Desenle birlikte tüm yolu eşleştirmemek daha iyi olur, ancak yalnızca dosya adıdır, çünkü model yolun başka bir yerinde olduğunda, her şeyi istemeden silersiniz. Ayrıca, desen dilinin "yeniden" ve ör. 'Bash'. İlgili bir düzenleme önereceğim. Boş dizinleri bu şekilde kaldırırsanız bir tadı meselesidir, çünkü rm 'den önce boş olan boş dizinleri de silecektir, yani genellikle kasıtsız siler. – flaschbier

0

Bu soruna çok daha basit bir çözüm bulmak için Popen(["rm " + file_name + "*.ext"], shell=True, stdout=PIPE).communicate() buluyorum. Bu, enjeksiyon saldırılarına eğilimli olsa da, programınız bunu dahili olarak kullanıyorsa herhangi bir sorun görmüyorum.

7

Bu nasıl?

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

Bu, özyineleme yapmaz ve joker karakterler (regex kullanmaz) kullanmaz. Python 3 ile çalışacak

+1

map(), üzerinde rastgele bir komut çalıştırmak yerine bir değerler kümesini dönüştürmek üzere tasarlanmıştır. Bu nedenle, bu en çok önerilen teknik değildir ve aslında Python 3'te başarısız olur, çünkü harita() şimdi işlevlerin hemen değerlendirilmesinden ziyade tekrar edilebilir duruma gelir. –

+2

Harita, python 3'ten itibaren bir jeneratör döndürür ve bu * işlevi kaldırır * işlevi kaldırır. –

31

glob yaklaşımı bir varyasyonu,:

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

Düzenleme:

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

os.remove bana bir sistem hatası veriyor (windows), bunun yerine shutil.rmtree'yi kullandım. – sparrow

+0

@sparrow Soru, bir desenle eşleşen tüm dizin ağaçlarını silmemek için bir desenle eşleşen * dosyaların * nasıl silindiği sorusudur. –

+0

Değişim 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

Bu kod sorunun çözülmesinin nasıl ve niçin bu sorunun nasıl çözüleceğine dair [bir açıklama] (// meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) sorusunu çözebilir. Gönderinizin kalitesi ve muhtemelen daha fazla oy ile sonuçlanır. Gelecekte okuyucular için soruyu cevapladığınızı unutmayın, sadece şimdi soran kişi için değil. Lütfen cevabınızı açıklama eklemek için düzenleyin ve hangi sınırlamaların ve varsayımların geçerli olduğuna dair bir gösterge verin. – Makyen

İlgili konular