Bagaimana cara menghapus / menghapus folder yang tidak kosong?

847

Saya mendapatkan kesalahan 'akses ditolak' ketika saya mencoba menghapus folder yang tidak kosong. Saya menggunakan perintah berikut dalam usaha saya: os.remove("/folder_name").

Apa cara paling efektif untuk menghapus / menghapus folder / direktori yang tidak kosong?

Amara
sumber
32
Perhatikan juga bahwa walaupun direktori itu kosong, os.remove akan gagal lagi, karena fungsi yang benar adalah os.rmdir.
tzot
Dan untuk rm -rfperilaku tertentu, lihat: stackoverflow.com/questions/814167/…
Ciro Santilli 郝海东 冠状 病 六四 六四 事件

Jawaban:

1349
import shutil

shutil.rmtree('/folder_name')

Referensi Perpustakaan Standar: shutil.rmtree .

Secara desain, rmtreegagal pada pohon folder yang berisi file read-only. Jika Anda ingin folder dihapus tanpa memperhatikan apakah itu berisi file read-only, maka gunakan

shutil.rmtree('/folder_name', ignore_errors=True)
ddaa
sumber
73
Catatan yang rmtreeakan gagal jika ada file read-only: stackoverflow.com/questions/2656322/…
Sridhar Ratnakumar
9
Ini tidak berfungsi untuk saya: Traceback (panggilan terakhir terakhir): File "foo.py", baris 31, di <module> shutil.rmtree (thistestdir) File "/usr/lib/python2.6/shutil.py ", baris 225, dalam rmtree onerror (os.rmdir, path, sys.exc_info ()) File" /usr/lib/python2.6/shutil.py ", baris 223, di rmtree os.rmdir (path) OSError: [Errno 90] Direktori tidak kosong: '/ path / to / rmtree'
Clayton Hughes
4
Clayton: kemungkinan besar, file ditambahkan bersamaan ketika rmtree sibuk menghapus hal-hal, "rm -rf" akan gagal sama.
ddaa
14
Adakah yang tahu mengapa fungsi ini tidak ada dalam paket os? Sepertinya os.rmdir tidak berguna. Adakah argumen bagus mengapa ini diterapkan seperti ini?
Malcolm
21
@ Malcolm Paket ini adalah pembungkus untuk fungsi OS. Pada sistem POSIX rmdir akan gagal jika direktori tidak kosong. Ubuntu dan Windows adalah contoh populer kepatuhan POSIX dalam hal ini.
Iain Samuel McLean Elder
138

Dari dokumen python pada 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))
kkubasik
sumber
1
Yah, mungkin aku salah tentang downmodding. Tapi saya bisa, saat ini saya pikir itu benar.
ddaa
3
@dada: Walaupun menggunakan shutil jelas merupakan cara termudah, pasti tidak ada yang aneh tentang solusi ini. Saya tidak akan membatalkan jawaban ini, tetapi saya hanya punya waktu untuk membatalkan downvote Anda :)
Jeremy Cantrell
7
Kode itu sendiri adalah pythonic. Menggunakannya alih-alih shutil.rmtree dalam program nyata akan menjadi unpythonic: itu akan mengabaikan "satu cara yang jelas untuk melakukannya". Bagaimanapun, ini adalah semantik, menghapus downmod.
ddaa
2
@dada Apakah unpythonic ingin mencatat setiap file atau direktori yang dihapus? Saya tidak yakin bagaimana melakukan itu dengan shutil.rmtree?
Jonathan Komar
4
@dada Itu adalah makanan untuk dipikirkan yaitu retorika. Saya tahu apa yang saya lakukan. Saya hanya berpikir Anda mungkin ingin mempertimbangkan kembali "cara yang jelas untuk melakukannya" dengan memberikan alasan mengapa shutil.rmtree mungkin bukan "fit" yang tepat.
Jonathan Komar
112
import shutil
shutil.rmtree(dest, ignore_errors=True)
Siva Mandadi
sumber
1
Ini jawaban yang benar. Di sistem saya, meskipun saya mengatur segala sesuatu di folder tertentu untuk menulis-baca, saya mendapatkan kesalahan ketika saya mencoba untuk menghapus. ignore_errors=Truememecahkan masalah.
Aventinus
3
Dalam jawaban saya, onerrorparameter yang digunakan bukan ignore_errors. Dengan cara ini, file hanya baca dihapus daripada diabaikan.
Dave Chandler
Ya, ini tidak akan menghapus file karena kesalahan. Jadi pada dasarnya seluruh rmtree()metode ini diabaikan.
Juha Untinen
2
Ini seharusnya merupakan suntingan kecil untuk jawaban yang diterima 6 tahun sebelumnya, bukan jawaban baru. Saya akan melakukan ini sekarang.
Jean-François Corbett
22

dari python 3.4 Anda dapat menggunakan:

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

dimana pthsebuah pathlib.Pathinstance. Bagus, tapi mungkin bukan yang tercepat.

yota
sumber
10

Dari docs.python.org :

Contoh ini menunjukkan cara menghapus pohon direktori pada Windows di mana beberapa file memiliki bit set read-only. Ini menggunakan panggilan balik onerror untuk menghapus sedikit readonly dan mencoba kembali menghapus. Kegagalan berikutnya akan menyebar.

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)
Dave Chandler
sumber
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) 

Jika ign_errors diatur, kesalahan diabaikan; jika tidak, jika onerror diset, ia dipanggil untuk menangani kesalahan dengan argumen (func, path, exc_info) di mana func adalah os.listdir, os.remove, atau os.rmdir; path adalah argumen untuk fungsi yang menyebabkannya gagal; dan exc_info adalah tuple yang dikembalikan oleh sys.exc_info (). Jika ignor_error salah dan onerror adalah Tidak ada, pengecualian akan dimunculkan kode enter.enter di sini

RY Zheng
sumber
Menurut dokumen , Pengecualian yang diajukan oleh onerror tidak akan ditangkap, jadi saya tidak yakin kenaikan gaji Anda memasukkan kode di sini berarti apa-apa.
kmarsh 15
-1. Ini tampaknya terlalu rumit dibandingkan dengan jawaban Dave Chandler. Juga, jika kita ingin menghapus readonly, kita tidak perlu membuat file dapat dieksekusi.
idbrii
7

Berdasarkan jawaban kkubasik, periksa apakah folder ada sebelum dihapus, lebih kuat

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")
Charles Chow
sumber
6
ini memperkenalkan kemungkinan kondisi balapan
Corey Goldberg
1
menurut sebagian besar pythonic-way-to-delete-a-file-yang-mungkin-tidak-ada , lebih baik untuk trymenghapus dan menangani exceptdaripada memanggil exists()dulu
TT
6

jika Anda yakin, bahwa Anda ingin menghapus seluruh pohon dir, dan tidak lagi tertarik pada isi dir, maka merangkak untuk seluruh pohon dir adalah kebodohan ... cukup panggil perintah OS asli dari python untuk melakukan itu. Ini akan lebih cepat, efisien dan lebih sedikit memakan memori.

RMDIR c:\blah /s /q 

atau * nix

rm -rf /home/whatever 

Dengan python, kode akan terlihat seperti ..

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])
SORE
sumber
33
-1. Inti dari penggunaan shutil.rmdiradalah untuk melindungi Anda dari jenis sistem operasi.
mtrw
3
Saya mengerti konsepnya, tetapi ketika seseorang sangat menyadari tentang fakta bahwa dia ingin menghapus folder sepenuhnya, lalu apa gunanya merangkak seluruh pohon file? shutil.rmdir secara khusus memanggil os.listdir (), os.path.islink () dll. beberapa pemeriksaan yang tidak benar-benar selalu dibutuhkan, karena yang diperlukan hanyalah memutus simpul sistem file. Selain beberapa sistem build, seperti MSWindows untuk pengembangan MSAuto / WinCE, maka shtuil.rmdir akan selalu gagal, karena pengembangan berbasis batch MSAuto mengunci beberapa file build aneh saat keluar yang tidak berhasil, dan hanya rmdir / S / Q atau restart yang membantu membersihkan mereka.
PM
2
ya, hanya rm lebih dekat ke kernel, menggunakan lebih sedikit waktu, memori dan cpu ..... dan seperti yang saya katakan, alasan saya untuk menggunakan metode ini adalah karena kunci yang ditinggalkan oleh MSAuto batch build scripts ...
PM
3
Ya, tetapi menggunakan shutil membuat kode lintas-platform dan mengaburkan detail platform.
xshoppyx
2
Saya tidak berpikir jawaban ini harus turun memilih di bawah 1 karena memberikan referensi yang sangat bagus untuk bekerja di sekitar situasi tertentu di mana pembaca mungkin tertarik Jadi meskipun saya tidak perlu menggunakan ini, saya sekarang tahu itu bisa dilakukan dan bagaimana caranya.
kmcguire
5

Hanya beberapa opsi python 3.5 untuk menyelesaikan jawaban di atas. (Saya ingin sekali menemukannya di sini).

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

Hapus folder jika kosong

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

Hapus juga folder jika berisi file ini

    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)

hapus folder jika hanya berisi file .srt atau .txt

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

Hapus folder jika ukurannya kurang dari 400kb:

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")
JinSnow
sumber
4
Harap perbaiki indentatyion dan kodeif files[0]== "desktop.ini" or:
Mr_and_Mrs_D
5

Saya ingin menambahkan pendekatan "pure pathlib":

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

Ini bergantung pada fakta yang Pathdapat dipesan, dan jalur yang lebih panjang akan selalu mengurutkan dari jalur yang lebih pendek, sama seperti str. Oleh karena itu, direktori akan datang sebelum file. Jika kita membalikkan pengurutan, file kemudian akan datang sebelum wadah masing-masing, sehingga kita dapat dengan mudah memutuskan tautan / rmdir mereka satu per satu dengan satu pass.

Manfaat:

  • BUKAN mengandalkan binari eksternal: semuanya menggunakan modul yang termasuk baterai Python (Python> = 3.6)
  • Cepat dan hemat memori: Tidak ada tumpukan rekursi, tidak perlu memulai subproses
  • Ini lintas platform (setidaknya, itulah yang pathlibdijanjikan dalam Python 3.6; tidak ada operasi di atas yang dinyatakan tidak berjalan pada Windows)
  • Jika diperlukan, seseorang dapat melakukan pendataan yang sangat terperinci, misalnya, mencatat setiap penghapusan saat itu terjadi.
pepoluan
sumber
dapatkah Anda memberikan contoh penggunaan misalnya. del_dir (Path ())? Terima kasih
lcapra
@lcapra Sebut saja dengan direktori untuk menghapus sebagai argumen pertama.
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)
menakjubkan di sana
sumber
Sangat bagus untuk membuat skrip yang menempatkan file dalam quarenteen sebelum menghapusnya secara membabi buta.
racribeiro
3

Jika Anda tidak ingin menggunakan shutilmodul, Anda bisa menggunakan osmodul.

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
Byron Filer
sumber
2
os.removetidak dapat menghapus direktori sehingga ini akan naik OsErrorjika directoryToRemoveberisi subdirektori.
Eponim
#pronetoraceconditions
kapad
3

Sepuluh tahun kemudian dan menggunakan Python 3.7 dan Linux masih ada beberapa cara untuk melakukan ini:

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

Pada dasarnya itu menggunakan modul subproses Python untuk menjalankan skrip bash $ rm -rf '/path/to/your/dirseolah-olah Anda menggunakan terminal untuk menyelesaikan tugas yang sama. Ini tidak sepenuhnya Python, tetapi bisa diselesaikan.

Alasan saya memasukkan pathlib.Pathcontoh adalah karena dalam pengalaman saya itu sangat berguna ketika berhadapan dengan banyak jalur yang berubah. Langkah-langkah tambahan mengimpor pathlib.Pathmodul dan mengubah hasil akhir menjadi string sering kali lebih murah bagi saya untuk waktu pengembangan. Akan lebih mudah jika Path.rmdir()datang dengan opsi arg untuk secara eksplisit menangani direktori tidak kosong.

RodogInfinite
sumber
Saya juga beralih ke pendekatan ini, karena saya mengalami masalah dengan rmtreedan folder tersembunyi seperti .vscode. Folder ini terdeteksi sebagai file teks dan kesalahannya memberi tahu saya bahwa file ini adalah busydan tidak dapat dihapus.
Daniel Eisenreich
2

Untuk menghapus folder meskipun itu mungkin tidak ada (menghindari kondisi balapan dalam jawaban Charles Chow ) tetapi masih memiliki kesalahan ketika hal-hal lain salah (mis. Masalah izin, kesalahan baca disk, file bukan direktori)

Untuk Python 3.x:

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)

Kode Python 2.7 hampir sama:

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)
Eponim
sumber
1

Dengan os.walk saya akan mengusulkan solusi yang terdiri dari 3 panggilan Python satu-liner:

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

Script pertama chmod's semua sub-direktori, script kedua chmod's semua file. Kemudian skrip ketiga menghapus semuanya tanpa halangan.

Saya telah menguji ini dari "Shell Script" di pekerjaan Jenkins (saya tidak ingin menyimpan skrip Python baru ke dalam SCM, itu sebabnya mencari solusi satu baris) dan itu bekerja untuk Linux dan Windows.

Alexander Samoylov
sumber
Dengan pathlib, Anda dapat menggabungkan dua langkah pertama menjadi satu:[p.chmod(0o666) for p in pathlib.Path(_path_).glob("**/*")]
pepoluan
0

Anda dapat menggunakan perintah os.system untuk kesederhanaan:

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

Seperti yang sudah jelas, itu benar-benar memanggil terminal sistem untuk menyelesaikan tugas ini.


sumber
19
Maaf, ini tidak bergantung pada platform dan bergantung pada platform.
Ami Tavory
0

Saya telah menemukan cara yang sangat mudah untuk menghapus folder apa pun (Bahkan BUKAN Kosong) atau file di WINDOWS OS .

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

Untuk Windows, jika direktori tidak kosong, dan Anda memiliki file read-only atau Anda mendapatkan kesalahan

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

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

Ini setara untuk rm -rfdi Linux / Mac.

Kartik Raj
sumber