web-dev-qa-db-fra.com

Comment puis-je supprimer/supprimer un dossier qui n'est pas vide avec Python?

Un message d'erreur indiquant que l'accès est refusé lorsque je tente de supprimer un dossier qui n'est pas vide. J'ai utilisé la commande suivante dans ma tentative: os.remove("/folder_name")

Quel est le moyen le plus efficace de supprimer/supprimer un dossier/répertoire qui n'est pas vide?

717
Amara
import shutil

shutil.rmtree('/folder_name')

Référence de la bibliothèque standard: shutil.rmtree .

De par sa conception, rmtree échoue dans les arborescences de dossiers contenant des fichiers en lecture seule. Si vous souhaitez que le dossier soit supprimé, qu'il contienne ou non des fichiers en lecture seule, utilisez

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

Depuis the python docs on 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))
123
kkubasik
import shutil
shutil.rmtree(dest, ignore_errors=True)
99
Siva Mandadi

depuis python 3.4, vous pouvez utiliser:

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

pth est une instance pathlib.Path. Nice, mais peut-être pas le plus rapide.

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

Si ignore_errors est défini, les erreurs sont ignorées. sinon, si onerror est défini, il est appelé pour traiter l'erreur avec des arguments (func, path, exc_info) où func est os.listdir, os.remove ou os.rmdir; chemin est l'argument de cette fonction qui a provoqué son échec; et exc_info est un tuple renvoyé par sys.exc_info (). Si ignore_errors est false et onerror est None, une exception est déclenchée. Code ici

7
RongyanZheng

si vous êtes sûr de vouloir supprimer l’ensemble de l’arborescence de répertoires et que le contenu de dir n’est plus intéressé, l’exploration de l’arborescence de répertoires entière est stupide ... appelez simplement la commande native OS à partir de python pour le faire. Ce sera plus rapide, efficace et moins gourmand en mémoire. 

RMDIR c:\blah /s /q 

ou * nix 

rm -rf /home/whatever 

En python, le code ressemblera à ..

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])
5
P M

De docs.python.org :

Cet exemple montre comment supprimer une arborescence de répertoires sous Windows où certains fichiers ont leur bit en lecture seule. Il utilise onerror callback pour effacer le bit en lecture seule et réessayer la suppression. Tout l'échec suivant se propagera.

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

Juste quelques options de python 3.5 pour compléter les réponses ci-dessus. (J'aurais aimé les trouver ici).

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

Supprimer le dossier s'il est vide

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

Supprimer aussi le dossier s'il contient ce fichier

    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)

supprime un dossier s'il ne contient que des fichiers .srt ou .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")

Supprimer le dossier si sa taille est inférieure à 400 Ko:

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

Sur la base de la réponse de kkubasik, vérifiez si le dossier existe avant de le supprimer, plus robuste

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")
4
Charles Chow

Si vous ne souhaitez pas utiliser le module shutil, vous pouvez simplement utiliser le module os.

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
3
Byron Filer
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)
2
amazingthere

Vous pouvez utiliser la commande os.system pour plus de simplicité:

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

Comme il est évident, il appelle en fait le terminal système pour accomplir cette tâche.

2
user5449023

J'aimerais ajouter une approche "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()

Cela repose sur le fait que Path est ordonnable, et les chemins les plus longs seront toujours triés après les chemins les plus courts, tout comme str. Par conséquent, les répertoires viendront avant les fichiers. Si nous inversons , les fichiers seront alors placés avant leurs conteneurs respectifs, afin que nous puissions simplement dissocier/rmdir les un par un avec un passage.

Avantages:

  • Il ne repose PAS sur des fichiers binaires externes: tout utilise les modules inclus dans les batteries de Python (Python> = 3.6)
  • C'est rapide et efficace en termes de mémoire: pas de pile de récursivité, pas besoin de démarrer un sous-processus
  • C'est multiplateforme (du moins, c'est ce que pathlib promet dans Python 3.6; aucune opération ci-dessus ne doit être exécutée sous Windows)
  • Si nécessaire, vous pouvez effectuer une journalisation très granulaire, par exemple en enregistrant chaque suppression en temps réel.
1
pepoluan

Avec os.walk, je proposerais la solution qui consiste en 3 appels Python à une ligne:

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

Le premier script contient tous les sous-répertoires de chmod, le second script contient tous les fichiers. Ensuite, le troisième script supprime tout sans aucun obstacle.

J'ai testé cela à partir du "script shell" dans un travail Jenkins (je ne voulais pas stocker un nouveau script Python dans SCM, c'est pourquoi nous avons recherché une solution à une ligne) et cela fonctionnait sous Linux et Windows.

1
Alexander Samoylov

Pour supprimer un dossier même s'il n'existe peut-être pas (éviter la condition de concurrence critique dans réponse de Charles Chow ) mais avoir toujours des erreurs lorsque d'autres problèmes se produisent (par exemple, problèmes d'autorisation, erreur de lecture du disque, le fichier n'est pas un répertoire)

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

Le code Python 2.7 est presque le même:

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
Eponymous

Dix ans plus tard, avec Python 3.7 et Linux, il existe toujours différentes façons de le faire:

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

Il utilise essentiellement le module de sous-processus de Python pour exécuter le script bash $ rm -rf '/path/to/your/dir comme si vous utilisiez le terminal pour accomplir la même tâche. Ce n'est pas entièrement en Python, mais cela se fait. 

La raison pour laquelle j'ai inclus l'exemple pathlib.Path est que, d'après mon expérience, il est très utile pour gérer de nombreux chemins qui changent. Les étapes supplémentaires d'importation du module pathlib.Path et de conversion des résultats finaux en chaînes représentent souvent un coût inférieur pour le temps de développement. Il serait pratique que Path.rmdir() vienne avec une option arg pour gérer explicitement les répertoires non vides.

0
RodogInfinite

Pour Windows, si le répertoire n’est pas vide et que vous avez des fichiers en lecture seule ou des erreurs telles que

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

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

C'est équivalent pour rm -rf sous Linux/Mac.

0
Kartik Raj

J'ai trouvé un moyen très facile de supprimer n'importe quel dossier (même PAS vide) ou fichier sur WINDOWS OS .

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