Boş olmayan bir klasörü nasıl silebilir / silebilirim?


847

Boş olmayan bir klasörü silmeye çalıştığımda 'erişim reddedildi' hatası alıyorum. Benim girişimi aşağıdaki komutu kullanılır: os.remove("/folder_name").

Boş olmayan bir klasörü / dizini silmenin / silmenin en etkili yolu nedir?


32
Ayrıca, dizin boş olsa bile, doğru işlev os.rmdir olduğundan os.remove öğesinin yeniden başarısız olacağını unutmayın.
tzot

Yanıtlar:


1348
import shutil

shutil.rmtree('/folder_name')

Standart Kütüphane Referansı: shutil.rmtree .

Tasarım gereği, rmtreesalt okunur dosyaları içeren klasör ağaçlarında başarısız olur. Klasörün salt okunur dosyalar içerip içermediğine bakılmaksızın silinmesini istiyorsanız,

shutil.rmtree('/folder_name', ignore_errors=True)

73
rmtree
Salt

9
Bu benim için işe yaramıyor: Geri izleme (en son çağrı): <module> shutil.rmtree (thistestdir) Dosyasında "foo.py", satır 31 dosyası "/usr/lib/python2.6/shutil.py ", satır 225, rmtree onerror'da (os.rmdir, yol, sys.exc_info ()) Dosya" /usr/lib/python2.6/shutil.py ", satır 223, rmtree os.rmdir (yol) OSError: [Errno 90] Dizin boş değil: '/ path / to / rmtree'
Clayton Hughes

4
Clayton: büyük olasılıkla, rmtree bir şeyleri silmekle meşgulken bir dosya eşzamanlı olarak eklendi, "rm -rf" aynı başarısız olur.
ddaa

13
Bu işlevin neden os paketinde olmadığını bilen var mı? Görünüşe göre os.rmdir oldukça işe yaramaz. Neden bu şekilde uygulandığına dair iyi bir tartışma var mı?
Malcolm

21
@Malcolm Paket, işletim sistemi işlevleri için bir paketleyicidir. On POSIX sistemlerinde Rmdir dizin boş değilse başarısız olacaktır. Ubuntu ve Windows , bu açıdan POSIX uyumluluğunun popüler örnekleridir.
Iain Samuel McLean Elder

138

Gönderen piton docs üzerinde os.walk():

# Delete everything reachable from the directory named in 'top',
# assuming there are no symbolic links.
# CAUTION:  This is dangerous!  For example, if top == '/', it
# could delete all your disk files.
import os
for root, dirs, files in os.walk(top, topdown=False):
    for name in files:
        os.remove(os.path.join(root, name))
    for name in dirs:
        os.rmdir(os.path.join(root, name))

1
Belki de downmodding yanılıyorum. Ama yapabilirim, şu anda doğru olduğunu düşünüyorum.
ddaa

3
@ddaa: Shutil kullanmak kesinlikle en kolay yol olsa da, kesinlikle bu çözüm hakkında tek sesli bir şey yok. Bu cevabı iptal edemezdim, ama sadece downvote'unuzu iptal etmek için bu zamanım var :)
Jeremy Cantrell

7
Kodun kendisi pitoniktir. Gerçek bir programda shutil.rmtree yerine bunu kullanmanın tek anlamı yoktur: bu "bunu yapmanın bariz bir yolu" nu göz ardı ederdi. Her neyse, bu anlambilimdir, downmod kaldırılır.
ddaa

2
@ddaa Silinen her dosyayı veya dizini günlüğe kaydetmek istemiyor mu? Bunu shutil.rmtree ile nasıl yapacağımdan emin değilim?
Jonathan Komar

4
@ ddaa Düşünce için yiyecek, yani retorikti. Ne yaptığımı biliyorum. Ben sadece shutil.rmtree doğru "uygun" olmayabilir bir neden sağlayarak "bunu yapmanın bariz yolu" yeniden düşünmek isteyebilirsiniz düşündüm.
Jonathan Komar

112
import shutil
shutil.rmtree(dest, ignore_errors=True)

1
Bu doğru cevap. Sistemimde, belirli bir klasördeki her şeyi yazma-okumaya ayarlasam da silmeye çalıştığımda bir hata alıyorum. ignore_errors=Truesorunu çözer.
Aventinus

3
Cevabımda onerrorparametre yerine kullanılır ignore_errors. Bu şekilde salt okunur dosyalar yoksayılmak yerine silinir.
Dave Chandler

Evet, bu hatalı dosyaları silmez. Temel olarak tüm rmtree()yöntem göz ardı edilir.
Juha Untinen

1
Bu, 6 yıl önce kabul edilen cevap için küçük bir düzenleme olmalı, daha ziyade yeni bir cevap olmalıdır. Bunu şimdi yapacağım.
Jean-François Corbett

22

python 3.4'ten şunları kullanabilirsiniz:

import pathlib

def delete_folder(pth) :
    for sub in pth.iterdir() :
        if sub.is_dir() :
            delete_folder(sub)
        else :
            sub.unlink()
    pth.rmdir() # if you just want to delete dir content, remove this line

pthbir pathlib.Pathörnek nerede . Güzel, ama en hızlı olmayabilir.


10

Gönderen docs.python.org :

Bu örnek, bazı dosyaların salt okunur bitlerinin ayarlandığı Windows'ta bir dizin ağacının nasıl kaldırılacağını gösterir. Salt okunur biti temizlemek ve kaldırmayı yeniden denemek için hata geri aramasını kullanır. Sonraki hatalar yayılır.

import os, stat
import shutil

def remove_readonly(func, path, _):
    "Clear the readonly bit and reattempt the removal"
    os.chmod(path, stat.S_IWRITE)
    func(path)

shutil.rmtree(directory, onerror=remove_readonly)

7
import os
import stat
import shutil

def errorRemoveReadonly(func, path, exc):
    excvalue = exc[1]
    if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
        # change the file to be readable,writable,executable: 0777
        os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)  
        # retry
        func(path)
    else:
        # raiseenter code here

shutil.rmtree(path, ignore_errors=False, onerror=errorRemoveReadonly) 

İgnore_errors ayarlanırsa hatalar yoksayılır; aksi takdirde, hata ayarlanmışsa, hatayı os.listdir, os.remove veya os.rmdir olan bağımsız değişkenlerle (func, path, exc_info) işlemek için çağrılır; yol, başarısız olmasına neden olan bu işleve yapılan argümandır; ve exc_info, sys.exc_info () tarafından döndürülen bir demettir. İgnore_errors yanlışsa ve hata Yok ise, bir istisna ortaya çıkar. Buraya kod girin


Dokümanlara göre , tarafından yapılan istisnalar yakalanmayacak, bu yüzden kodunuzu buraya girdiğinizin bir şey ifade ettiğinden emin değilim .
kmarsh

-1. Bu, Dave Chandler'ın cevabına kıyasla aşırı karmaşık görünüyor. Ayrıca, salt okunur olarak kaldırmak istiyorsak, dosyaları yürütülebilir yapmamız gerekmez.
idbrii

7

Kkubasik'in cevabına dayanarak, kaldırmadan önce klasörün var olup olmadığını kontrol edin, daha sağlam

import shutil
def remove_folder(path):
    # check if folder exists
    if os.path.exists(path):
         # remove if exists
         shutil.rmtree(path)
    else:
         # throw your exception to handle this special scenario
         raise XXError("your exception") 
remove_folder("/folder_name")

6
Bu olası bir yarış koşulu getiriyor
Corey Goldberg

1
var olmayan bir dosya silmek için en pythonic-yol-silmek-dosya göre , ilk çağrı çağırmak yerine trykaldırmak ve işlemek için tercih edilebilirexceptexists()
TT--

6

Eğer dir ağacının tamamını silmek istediğinizden eminseniz ve artık dir içeriğiyle ilgilenmiyorsanız, tüm dir ağacı için tarama aptallıktır ... bunu yapmak için python'dan yerel işletim sistemi komutunu çağırmanız yeterlidir. Daha hızlı, verimli ve daha az bellek tüketir.

RMDIR c:\blah /s /q 

veya * nix

rm -rf /home/whatever 

Python'da kod şöyle görünecektir ..

import sys
import os

mswindows = (sys.platform == "win32")

def getstatusoutput(cmd):
    """Return (status, output) of executing cmd in a shell."""
    if not mswindows:
        return commands.getstatusoutput(cmd)
    pipe = os.popen(cmd + ' 2>&1', 'r')
    text = pipe.read()
    sts = pipe.close()
    if sts is None: sts = 0
    if text[-1:] == '\n': text = text[:-1]
    return sts, text


def deleteDir(path):
    """deletes the path entirely"""
    if mswindows: 
        cmd = "RMDIR "+ path +" /s /q"
    else:
        cmd = "rm -rf "+path
    result = getstatusoutput(cmd)
    if(result[0]!=0):
        raise RuntimeError(result[1])

33
-1. Kullanmanın shutil.rmdirasıl amacı sizi işletim sisteminin türünden yalıtmaktır.
mtrw

3
Kavramı anlıyorum, ancak kişi klasörü tamamen silmek istediğinin farkında olduğunda, tüm dosya ağacını taramanın anlamı nedir? shutil.rmdir özellikle os.listdir (), os.path.islink () vb. MSAuto / WinCE geliştirme için MSWindows gibi bazı derleme sistemlerinin yanı sıra, shtuil.rmdir neredeyse her zaman başarısız olacaktır, çünkü MSAuto toplu iş geliştirme başarısız çıkışta bazı garip derleme dosyalarını kilitler ve yalnızca rmdir / S / Q veya yeniden başlatma temizlemeye yardımcı olur onlar.
PM

2
evet, sadece rm yakın çekirdeğe, daha az zaman, bellek ve cpu kullanıyor ..... ve dediğim gibi kilitleri ... MSAuto toplu yapı komut geride bıraktığı çünkü beni bu yöntemi kullanmak için neden oldu
PM

3
Evet, ancak shutil kullanmak kodu çapraz platform haline getirir ve platform ayrıntılarını özetler.
xshoppyx

2
Bu cevabın 1'in altında oylanması gerektiğini düşünmüyorum, çünkü bir okuyucunun ilgilenebileceği belirli durumlar için çok güzel bir referans sağlıyor. Bu yüzden bunu kullanmama gerek olmasa da artık nasıl yapılacağını biliyorum.
kmcguire

5

Yukarıdaki cevapları tamamlamak için sadece bazı python 3.5 seçenekleri. (Onları burada bulmayı çok isterdim).

import os
import shutil
from send2trash import send2trash # (shutil delete permanently)

Boşsa klasörü sil

root = r"C:\Users\Me\Desktop\test"   
for dir, subdirs, files in os.walk(root):   
    if subdirs == [] and files == []:
           send2trash(dir)
           print(dir, ": folder removed")

Bu dosyayı içeriyorsa klasörü de sil

    elif subdirs == [] and len(files) == 1: # if contains no sub folder and only 1 file 
        if files[0]== "desktop.ini" or:  
            send2trash(dir)
            print(dir, ": folder removed")
        else:
            print(dir)

yalnızca .srt veya .txt dosyaları içeriyorsa klasörü sil

    elif subdirs == []: #if dir doesn’t contains subdirectory
        ext = (".srt", ".txt")
        contains_other_ext=0
        for file in files:
            if not file.endswith(ext):  
                contains_other_ext=True
        if contains_other_ext== 0:
                send2trash(dir)
                print(dir, ": dir deleted")

Boyutu 400kb'den küçükse klasörü sil:

def get_tree_size(path):
    """Return total size of files in given path and subdirs."""
    total = 0
    for entry in os.scandir(path):
        if entry.is_dir(follow_symlinks=False):
            total += get_tree_size(entry.path)
        else:
            total += entry.stat(follow_symlinks=False).st_size
    return total


for dir, subdirs, files in os.walk(root):   
    If get_tree_size(dir) < 400000:  # ≈ 400kb
        send2trash(dir)
    print(dir, "dir deleted")

4
Lütfen girinti ve kodu düzeltinif files[0]== "desktop.ini" or:
Mr_and_Mrs_D

5

Bir "saf pathlib" yaklaşımı eklemek istiyorum:

from pathlib import Path
from typing import Union

def del_dir(target: Union[Path, str], only_if_empty: bool = False):
    target = Path(target).expanduser()
    assert target.is_dir()
    for p in sorted(target.glob('**/*'), reverse=True):
        if not p.exists():
            continue
        p.chmod(0o666)
        if p.is_dir():
            p.rmdir()
        else:
            if only_if_empty:
                raise RuntimeError(f'{p.parent} is not empty!')
            p.unlink()
    target.rmdir()

Bu, düzenlenebilir olan gerçeğe dayanır Pathve daha uzun yollar her zamanki gibi daha kısa yollardan sonra sıralanır str. Bu nedenle, dizinler dosyalardan önce gelir. Biz ise ters tür dosyalar daha sonra, kendi konteynerlerin önce gelecek yüzden biz sadece bağlantı kaldırma / Rmdir onları tek geçişle teker teker.

Yararları:

  • Harici ikili dosyalara güvenmiyor: her şey Python'un piller dahil modüllerini kullanıyor (Python> = 3.6)
  • Hızlı ve bellek açısından verimli: Özyineleme yığını yok, alt işlem başlatmaya gerek yok
  • Platformlar arası (en azından pathlibPython 3.6'da vaat eden şey budur ; yukarıda hiçbir işlemin Windows'ta çalışmadığı belirtilmedi)
  • Gerekirse, çok ayrıntılı bir günlük kaydı yapılabilir, örn. Her silme işleminin gerçekleştiği anda günlüğe kaydedilmesi.

ayrıca bir kullanım örneği sağlayabilir misiniz? del_dir (Yol ())? Teşekkürler
lcapra

@lcapra İlk argüman olarak silmek için dizinde aramanız yeterlidir.
pepoluan

3
def deleteDir(dirPath):
    deleteFiles = []
    deleteDirs = []
    for root, dirs, files in os.walk(dirPath):
        for f in files:
            deleteFiles.append(os.path.join(root, f))
        for d in dirs:
            deleteDirs.append(os.path.join(root, d))
    for f in deleteFiles:
        os.remove(f)
    for d in deleteDirs:
        os.rmdir(d)
    os.rmdir(dirPath)

Körü körüne kaldırmadan önce dosyayı ocağa koyan komut dosyası oluşturmak harika.
racribeiro

3

shutilModülü kullanmak istemiyorsanız , sadece osmodülü kullanabilirsiniz .

from os import listdir, rmdir, remove
for i in listdir(directoryToRemove):
    os.remove(os.path.join(directoryToRemove, i))
rmdir(directoryToRemove) # Now the directory is empty of files

2
os.removedizinleri kaldıramaz, bu nedenle alt dizinler OsErrorvarsa directoryToRemoveyükselir.
İsimsiz

#pronetoraceconditions
kapad

3

On yıl sonra ve Python 3.7 ve Linux kullanarak bunu yapmanın hala farklı yolları var:

import subprocess
from pathlib import Path

#using pathlib.Path
path = Path('/path/to/your/dir')
subprocess.run(["rm", "-rf", str(path)])

#using strings
path = "/path/to/your/dir"
subprocess.run(["rm", "-rf", path])

Temelde $ rm -rf '/path/to/your/dir, aynı görevi gerçekleştirmek için terminali kullanıyormuş gibi bash betiğini çalıştırmak için Python'un alt işlem modülünü kullanıyor. Tamamen Python değil, ama hallediyor.

Ben dahil nedeni pathlib.Pathbu değişim birçok yolları ile uğraşırken benim durumumda çok yararlıdır, çünkü örnek olduğunu. pathlib.PathModülü içe aktarmanın ve son sonuçları dizelere dönüştürmenin ek adımları genellikle geliştirme süresi için daha düşük bir maliyettir. Path.rmdir()Boş olmayan dizinleri açıkça işlemek için bir arg seçeneğiyle gelmeniz uygun olur .


Ayrıca bu yaklaşıma geçtim, çünkü rmtreegibi sorunlarla ve gizli klasörlerle karşılaştım .vscode. Bu klasör metin dosyası olarak algılandı ve hata bana bu dosyanın busysilindiğini ve silinemediğini söyledi.
Daniel Eisenreich

2

Bir klasörü olmasa bile silmek için ( Charles Chow'un cevabındaki yarış koşulundan kaçınmak ) ancak diğer şeyler yanlış gittiğinde hala hatalar var (örneğin izin sorunları, disk okuma hatası, dosya bir dizin değil)

Python 3.x için:

import shutil

def ignore_absent_file(func, path, exc_inf):
    except_instance = exc_inf[1]
    if isinstance(except_instance, FileNotFoundError):
        return
    raise except_instance

shutil.rmtree(dir_to_delete, onerror=ignore_absent_file)

Python 2.7 kodu neredeyse aynı:

import shutil
import errno

def ignore_absent_file(func, path, exc_inf):
    except_instance = exc_inf[1]
    if isinstance(except_instance, OSError) and \
        except_instance.errno == errno.ENOENT:
        return
    raise except_instance

shutil.rmtree(dir_to_delete, onerror=ignore_absent_file)

1

Oswalk ile 3 adet tek katmanlı Python çağrısından oluşan çözümü öneririm:

python -c "import sys; import os; [os.chmod(os.path.join(rs,d), 0o777) for rs,ds,fs in os.walk(_path_) for d in ds]"
python -c "import sys; import os; [os.chmod(os.path.join(rs,f), 0o777) for rs,ds,fs in os.walk(_path_) for f in fs]"
python -c "import os; import shutil; shutil.rmtree(_path_, ignore_errors=False)"

İlk kod chmod'un tüm alt dizinleri, ikinci komut dosyası chmod'un tüm dosyaları. Sonra üçüncü senaryo hiçbir engel olmadan her şeyi kaldırır.

Ben bir Jenkins işinde "Shell Script" den test ettik (SCM içine yeni bir Python betiği depolamak istemedim, bu yüzden tek satırlık bir çözüm aradı) ve Linux ve Windows için çalıştı.


İle pathlib, ilk iki adımı bir araya getirebilirsiniz:[p.chmod(0o666) for p in pathlib.Path(_path_).glob("**/*")]
pepoluan

0

Basitlik için os.system komutunu kullanabilirsiniz:

import os
os.system("rm -rf dirname")

Açıkça görüldüğü gibi, aslında bu görevi yerine getirmek için sistem terminalini çağırır.


19
Üzgünüz, bu Unpythonic ve platforma bağlı.
Ami Tavory

0

Ben WINDOWS OS herhangi bir klasörü (Bile DEĞİL) veya dosyayı silmek için çok kolay bir yol buldum .

os.system('powershell.exe  rmdir -r D:\workspace\Branches\*%s* -Force' %CANDIDATE_BRANCH)

0

Windows için, dizin boş değilse ve salt okunur dosyalarınız varsa veya aşağıdaki gibi hatalar alıyorsanız

  • Access is denied
  • The process cannot access the file because it is being used by another process

Bunu dene, os.system('rmdir /S /Q "{}"'.format(directory))

rm -rfLinux / Mac için eşdeğerdir .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.