Jak usunąć zawartość folderu?

468

Jak mogę usunąć zawartość folderu lokalnego w Pythonie?

Obecny projekt dotyczy systemu Windows, ale chciałbym także zobaczyć * nix.

UnkwnTech
źródło
2
aby * nix był szczery, po prostu os.system('rm -rf folder')
użyłbym

Odpowiedzi:

441
import os, shutil
folder = '/path/to/folder'
for filename in os.listdir(folder):
    file_path = os.path.join(folder, filename)
    try:
        if os.path.isfile(file_path) or os.path.islink(file_path):
            os.unlink(file_path)
        elif os.path.isdir(file_path):
            shutil.rmtree(file_path)
    except Exception as e:
        print('Failed to delete %s. Reason: %s' % (file_path, e))
Nick Stinemon
źródło
4
Jeśli pracujesz z bardzo dużym katalogiem, a zwłaszcza katalogiem sieciowym w systemie Windows, i możesz kontrolować środowisko, w którym ten program działa, warto skorzystać z funkcji „os.scandir (folder)” Py3.5 zamiast listdir. Następnie składnia jest zupełnie inna, ale dość prosta do wdrożenia; chętnie go opublikuję, jeśli inni będą chcieli.
Michael Scott Cuthbert
Dostaję ostrzeżenie pylint z except Exception as e:tymi odczytami W0703: Catching too general exception Exception. Czy jest jakiś konkretniejszy wyjątek do złapania, czy powinienem go zignorować?
John Hany
7
@JohnHany, wierzę, że chcesz złapać OSError.
MikeB,
246

Możesz po prostu to zrobić:

import os
import glob

files = glob.glob('/YOUR/PATH/*')
for f in files:
    os.remove(f)

Oczywiście możesz użyć innego filtra w swojej ścieżce, na przykład: /YOU/PATH/*.txt do usunięcia wszystkich plików tekstowych z katalogu.

Blueicefield
źródło
12
@Blueicefield *nie będzie wyświetlał ukrytych plików, powinniśmy również dodaćglob.glob('path/.*)
satoru
5
chociaż aby usunąć listę plików, wydaje mi się prostsze:import sh; sh.rm(files)
Robin Winslow
2
Choć import sh; sh.rm(files)wygląda ładniej, możesz napotkać problemy, jeśli w katalogu jest więcej niż 1024 pliki.
Eugene
234

Możesz usunąć sam folder, a także całą jego zawartość, używając shutil.rmtree:

import shutil
shutil.rmtree('/path/to/folder')
shutil.rmtree(path, ignore_errors=False, onerror=None)


Usuń całe drzewo katalogów; ścieżka musi wskazywać na katalog (ale nie symboliczne łącze do katalogu). Jeśli parametr ignore_errors ma wartość true, błędy wynikające z nieudanych operacji usuwania zostaną zignorowane; w przypadku fałszu lub pominięcia, takie błędy są obsługiwane przez wywołanie procedury obsługi określonej przez onerror lub, jeśli zostanie pominięte, zgłoszą wyjątek.

Oli
źródło
270
Spowoduje to nie tylko usunięcie zawartości, ale także samego folderu. Nie sądzę, że o to pyta pytanie.
Iker Jimenez
3
Myślę, że to dobra odpowiedź. Dlaczego po prostu nie usuniesz zawartości i folderu, a następnie ponownie utworzysz folder?
cssndrx,
42
Ponieważ nowy katalog i stary nie będą takie same. Więc jeśli jakiś program siedzi w katalogu i czeka na rzeczy, dywan zostanie wyciągnięty spod niego.
Mike Cooper
30
Po prostu utwórz ponownie katalog po rmtree. Jakos.makedirs(dir)
Iulius Curt
3
@IuliusCurt nie, mam katalog zamontowany w pamięci RAM, muszę go opróżnić i niestety nie mogę go po prostu usunąć, a następnie utworzyć ponownie:OSError: [Errno 16] Device or resource busy
Arnaud P
80

Rozwijając odpowiedź mhawke, właśnie to zaimplementowałem. Usuwa całą zawartość folderu, ale nie sam folder. Testowany w systemie Linux z plikami, folderami i dowiązaniami symbolicznymi powinien również działać w systemie Windows.

import os
import shutil

for root, dirs, files in os.walk('/path/to/folder'):
    for f in files:
        os.unlink(os.path.join(root, f))
    for d in dirs:
        shutil.rmtree(os.path.join(root, d))
Iker Jimenez
źródło
1
Dlaczego „chodzić”, a nie tylko wyświetlać zawartość folderów?
Don
2
To poprawna odpowiedź, jeśli chcesz również usunąć katalogi. walksłuży do podziału katalogów na pliki, które muszą być obsługiwane w inny sposób. Możesz także użyć os.listdir, ale musisz ręcznie sprawdzić, czy każdy wpis jest katalogiem lub plikiem.
dkamins
7
Jest blisko, ale zarówno os.walk, jak i shutil.rmtree są rekurencyjne. os.walk jest niepotrzebny, ponieważ do wyczyszczenia potrzebujesz tylko plików i katalogów na najwyższym poziomie w katalogu. Wystarczy użyć instrukcji if na elementach w os.listdir, aby sprawdzić, czy każdy z nich jest plikiem czy katalogiem. Następnie użyj odpowiednio remove / unlink i rmtree.
Matthew Alpert
1
@MatthewAlpert Zauważ jednak, że os.walktutaj się nie powtórzy, ponieważ zwraca generator, tylko rekurencyjnie przegląda podkatalogi, gdy próbujesz go rozwinąć, a do czasu pierwszej iteracji tej pętli nie ma podkatalogów pozostawiony do obejrzenia. Zasadniczo os.walkjest tutaj używany jako alternatywny sposób odróżnienia folderów najwyższego poziomu od plików najwyższego poziomu; rekurencja nie jest używana i nie ponosimy za nią kosztów wydajności. Jest to jednak ekscentryczne i zgadzam się, że proponowane przez ciebie podejście jest lepsze po prostu dlatego, że jest bardziej wyraźne i czytelne.
Mark Amery
47

Używanie rmtreei odtwarzanie folderu może działać, ale podczas usuwania i natychmiastowego odtwarzania folderów na dyskach sieciowych napotkałem błędy.

Proponowane rozwiązanie wykorzystujące walk nie działa, ponieważ służy rmtreedo usuwania folderów, a następnie może próbować użyć os.unlinkplików wcześniej znajdujących się w tych folderach. To powoduje błąd.

Opublikowane globrozwiązanie będzie również próbowało usunąć niepuste foldery, powodując błędy.

Sugeruję użycie:

folder_path = '/path/to/folder'
for file_object in os.listdir(folder_path):
    file_object_path = os.path.join(folder_path, file_object)
    if os.path.isfile(file_object_path) or os.path.islink(file_object_path):
        os.unlink(file_object_path)
    else:
        shutil.rmtree(file_object_path)
jgoeders
źródło
1
Twoje rozwiązanie spowoduje również błąd, jeśli istnieje dowiązanie symboliczne do innego katalogu.
Blueicefield,
@Blueicefield - Czy możesz podać przykład? Testowałem w systemie Linux przy użyciu pliku i folderu z dowiązaniem symbolicznym i nie byłem jeszcze w stanie spowodować błędu.
jgoeders
@jgoeders - Jeśli istnieje dowiązanie symboliczne do katalogu, os.path.isfile()powróci False(ponieważ następuje dowiązanie symboliczne), a w końcu wywołasz shutil.rmtree()dowiązanie symboliczne, które się podniesie OSError("Cannot call rmtree on a symbolic link").
Rockallite,
1
@Rockallite naprawione przez check to islink
kevinf
1
Ponadto: @kevinf słusznie wskazuje na potrzebę islinksprawdzenia tutaj, aby poprawnie obsługiwać dowiązania symboliczne do katalogów. Dodałem taki czek do zaakceptowanej odpowiedzi.
Mark Amery
20

To:

  • usuwa wszystkie dowiązania symboliczne
    • martwe linki
    • linki do katalogów
    • linki do plików
  • usuwa podkatalogi
  • nie usuwa katalogu nadrzędnego

Kod:

for filename in os.listdir(dirpath):
    filepath = os.path.join(dirpath, filename)
    try:
        shutil.rmtree(filepath)
    except OSError:
        os.remove(filepath)

Jak wiele innych odpowiedzi, nie próbuje to dostosowywać uprawnień, aby umożliwić usuwanie plików / katalogów.

Jon Chu
źródło
15

Jako oneliner:

import os

# Python 2.7
map( os.unlink, (os.path.join( mydir,f) for f in os.listdir(mydir)) )

# Python 3+
list( map( os.unlink, (os.path.join( mydir,f) for f in os.listdir(mydir)) ) )

Bardziej niezawodnym rozwiązaniem uwzględniającym również pliki i katalogi byłoby (2.7):

def rm(f):
    if os.path.isdir(f): return os.rmdir(f)
    if os.path.isfile(f): return os.unlink(f)
    raise TypeError, 'must be either file or directory'

map( rm, (os.path.join( mydir,f) for f in os.listdir(mydir)) )
fmonegaglia
źródło
1
w przypadku dużych operacji użycie generatora może być frakcjonalnie bardziej wydajnemap( os.unlink, (os.path.join( mydir,f) for f in os.listdir(mydir)) )
user25064
faktycznie próbując tego użyć, zdałem sobie sprawę, że obiekt mapy musi być iterowany, więc wymagane jest wywołanie list (lub coś, co będzie iterować), jaklist(map(os.unlink, (os.path.join( mydir,f) for f in os.listdir(mydir))))
user25064
Pierwsza zawarta w odpowiedzi, druga nie ma dla mnie sensu. Dlaczego powinieneś iterować po funkcji zamapowanej na iterowalną? Mapa to robi.
fmonegaglia,
1
W Python3, trzeba zawinąć mapw list rzeczywiście iteracyjne. Zobacz http://stackoverflow.com/questions/1303347/getting-a-map-to-return-a-list-in-python-3-x
paulwasit,
Ten na pewno nie zadziała, jeśli „mydir” zawiera co najmniej jeden folder, ponieważ unlink działa tylko dla plików ...
kupsef
14

Uwagi: na wypadek, gdyby ktoś głosował za moją odpowiedzią, muszę coś wyjaśnić.

  1. Każdy lubi krótkie i proste odpowiedzi. Czasami jednak rzeczywistość nie jest taka prosta.
  2. Wróć do mojej odpowiedzi. Wiem, że shutil.rmtree()można go użyć do usunięcia drzewa katalogów. Użyłem go wiele razy w swoich własnych projektach. Musisz jednak zdać sobie sprawę, że sam katalog również zostanie usuniętyshutil.rmtree() . Chociaż może to być akceptowalne dla niektórych, nie jest to poprawna odpowiedź na usunięcie zawartości folderu (bez skutków ubocznych) .
  3. Pokażę ci przykład skutków ubocznych. Załóżmy, że masz katalog z dostosowanymi bitami właściciela i trybu, w którym jest dużo treści. Następnie usuwasz go za pomocą shutil.rmtree()i odbudowuje się za pomocą os.mkdir(). Zamiast tego otrzymasz pusty katalog z domyślnymi (odziedziczonymi) bitami właściciela i trybu. Chociaż możesz mieć uprawnienia do usuwania zawartości, a nawet katalogu, możesz nie być w stanie przywrócić pierwotnego właściciela i bitów trybu w katalogu (np. Nie jesteś superużytkownikiem).
  4. Wreszcie, bądź cierpliwy i przeczytaj kod . Jest długi i brzydki (w zasięgu wzroku), ale udowodniono, że jest niezawodny i wydajny (w użyciu).

Oto długie i brzydkie, ale niezawodne i wydajne rozwiązanie.

Rozwiązuje kilka problemów, które nie zostały rozwiązane przez innych użytkowników:

  • Prawidłowo obsługuje łącza symboliczne, w tym nie wywołuje shutil.rmtree()łącza symbolicznego (które przejdzieos.path.isdir() test, jeśli zostanie dowiązany do katalogu; nawet wynik os.walk()zawiera również dowiązania symboliczne).
  • Ładnie obsługuje pliki tylko do odczytu.

Oto kod (jedyną przydatną funkcją jest clear_dir()):

import os
import stat
import shutil


# http://stackoverflow.com/questions/1889597/deleting-directory-in-python
def _remove_readonly(fn, path_, excinfo):
    # Handle read-only files and directories
    if fn is os.rmdir:
        os.chmod(path_, stat.S_IWRITE)
        os.rmdir(path_)
    elif fn is os.remove:
        os.lchmod(path_, stat.S_IWRITE)
        os.remove(path_)


def force_remove_file_or_symlink(path_):
    try:
        os.remove(path_)
    except OSError:
        os.lchmod(path_, stat.S_IWRITE)
        os.remove(path_)


# Code from shutil.rmtree()
def is_regular_dir(path_):
    try:
        mode = os.lstat(path_).st_mode
    except os.error:
        mode = 0
    return stat.S_ISDIR(mode)


def clear_dir(path_):
    if is_regular_dir(path_):
        # Given path is a directory, clear its content
        for name in os.listdir(path_):
            fullpath = os.path.join(path_, name)
            if is_regular_dir(fullpath):
                shutil.rmtree(fullpath, onerror=_remove_readonly)
            else:
                force_remove_file_or_symlink(fullpath)
    else:
        # Given path is a file or a symlink.
        # Raise an exception here to avoid accidentally clearing the content
        # of a symbolic linked directory.
        raise OSError("Cannot call clear_dir() on a symbolic link")
Rockallite
źródło
Nie rozumiem, w jakim kontekście zmiana trybu pliku ma sens. Na moim komputerze Mac, os.removew przeciwieństwie do rmnarzędzia, z przyjemnością usuwa pliki tylko do odczytu, o ile jesteś ich właścicielem. Tymczasem jeśli jest to plik, którego nie posiadasz, do którego masz dostęp tylko do odczytu, nie możesz go usunąć ani zmienić jego uprawnień. Nie znam żadnej sytuacji w żadnym systemie, w której nie można usunąć pliku tylko do odczytu, os.removeale można zmienić jego uprawnienia. Ponadto używasz lchmod, który nie istnieje na moim komputerze Mac, ani w systemie Windows zgodnie z jego dokumentacją. Dla jakiej platformy przeznaczony jest ten kod ?!
Mark Amery
14

Dziwi mnie, że nikt nie wspominał o niesamowitym pathlibwykonywaniu tej pracy.

Jeśli chcesz tylko usunąć pliki z katalogu, może to być oneliner

from pathlib import Path

[f.unlink() for f in Path("/path/to/folder").glob("*") if f.is_file()] 

Aby rekurencyjnie usunąć katalogi, możesz napisać coś takiego:

from pathlib import Path
from shutil import rmtree

for path in Path("/path/to/folder").glob("**/*"):
    if path.is_file():
        path.unlink()
    elif path.is_dir():
        rmtree(path)
Ochrypły
źródło
1
.iterdir()zamiast .glob(...)powinien również działać.
S. Kirby
11
import os
import shutil

# Gather directory contents
contents = [os.path.join(target_dir, i) for i in os.listdir(target_dir)]

# Iterate and remove each item in the appropriate manner
[os.remove(i) if os.path.isfile(i) or os.path.islink(i) else shutil.rmtree(i) for i in contents]

Wcześniejszy komentarz wspomina także o użyciu os.scandir w Python 3.5+. Na przykład:

import os
import shutil

with os.scandir(target_dir) as entries:
    for entry in entries:
        if entry.is_file() or entry.is_symlink():
            os.remove(entry.path)
        elif entry.is_dir():
            shutil.rmtree(entry.path)
Jacob Wan
źródło
1
os.path.isdir()nie jest prawidłowym sposobem na odróżnienie zwykłego katalogu od dowiązania symbolicznego. Wywołanie shutil.rmtree()dowiązania symbolicznego spowoduje OSErrorwyjątek.
Rockallite,
@Rockallite Thanks. Masz rację. Zaktualizowałem przykład.
Jacob Wan
8

Lepiej skorzystaj os.walk()z tego.

os.listdir()nie rozróżnia plików od katalogów i szybko będziesz mieć problemy z rozłączeniem ich. Istnieje dobry przykład os.walk()rekurencyjnego usuwania katalogu tutaj i wskazówki, jak dostosować go do swoich okoliczności.

Mahawke
źródło
6

Rozwiązałem problem w ten sposób:

import shutil
import os

shutil.rmtree(dirpath)
os.mkdir(dirpath)
ProfHase85
źródło
7
Ma to radykalnie inną semantykę od tego, o co pyta pytanie i nie powinno być uważane za prawidłową odpowiedź.
fatuhoku
1
Z szacunkiem uważam, że „Usuń zawartość folderu lokalnego” nie wymaga usunięcia samego folderu. Ten sam problem, co ta odpowiedź , z tą różnicą, że otrzymaliśmy wiele pozytywnych opinii!
fatuhoku
3
To tak, jakby odpowiedzieć na pytanie „W jaki sposób funkcja zwraca liczbę 1 w Pythonie?” z def return_a_one (): launch_some_nukes () return 1
fatuhoku 26.09.13
2
Oczywiście semantyka jest inna: ale równie dobrze możesz uznać to za inny sposób spojrzenia na problem. To rozwiązanie jest całkowicie poprawne, ponieważ rozwiązuje problem. Istnieje różnica w przykładzie „launch_some_nukes”: 1. Rozwiązanie jest krótsze i łatwiejsze niż zaakceptowane i w przeciwieństwie do cytowanej odpowiedzi jest prawidłowe. 2. odpowiednikiem „launch_some_nukes” w tym przypadku jest usunięcie i ponowne utworzenie folderu. Różnica między starym i nowym folderem to tylko numer i-węzła (prawdopodobnie nieistotny dla OP)
ProfHase85
2
Rujnuje
5

Jeszcze inne rozwiązanie:

import sh
sh.rm(sh.glob('/path/to/folder/*'))
Robin Winslow
źródło
1
Pamiętaj, że shnie jest częścią standardowej biblioteki i wymaga instalacji z PyPI, zanim będziesz mógł z niej korzystać. Ponadto, ponieważ faktycznie wywołuje rmto podproces, nie będzie działać w systemie Windows, gdzie rmnie istnieje. Zgłasza także wyjątek, jeśli folder zawiera jakieś podkatalogi.
Mark Amery
5

Wiem, że to stary wątek, ale znalazłem coś ciekawego na oficjalnej stronie Pythona. Wystarczy udostępnić kolejny pomysł na usunięcie całej zawartości katalogu. Ponieważ mam pewne problemy z autoryzacją podczas korzystania z shutil.rmtree () i nie chcę usuwać katalogu i odtwarzać go ponownie. Oryginalny adres to http://docs.python.org/2/library/os.html#os.walk . Mam nadzieję, że może komuś pomóc.

def emptydir(top):
    if(top == '/' or top == "\\"): return
    else:
        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))
Tracz
źródło
4

Aby usunąć wszystkie pliki w katalogu oraz jego podkatalogach, bez usuwania samych folderów, po prostu wykonaj następujące czynności:

import os
mypath = "my_folder" #Enter your path here
for root, dirs, files in os.walk(mypath):
    for file in files:
        os.remove(os.path.join(root, file))
Kevin Patel
źródło
3

Jeśli używasz systemu * nix, dlaczego nie skorzystać z polecenia systemowego?

import os
path = 'folder/to/clean'
os.system('rm -rf %s/*' % path)
silverbullettt
źródło
3
Ponieważ, jak stwierdzono w pytaniu: „Obecny projekt jest dla systemu Windows”
sox z Monicą
3

Całkiem intuicyjny sposób:

import shutil, os


def remove_folder_contents(path):
    shutil.rmtree(path)
    os.makedirs(path)


remove_folder_contents('/path/to/folder')
Manrique
źródło
3

Myślę, że ten kod działa. Nie spowoduje to usunięcia folderu i możesz użyć tego kodu do usunięcia plików o określonym rozszerzeniu.

import os
import glob

files = glob.glob(r'path/*')
for items in files:
    os.remove(items)
Kush Modi
źródło
3

Musiałem usunąć pliki z 3 oddzielnych folderów w jednym katalogu nadrzędnym:

directory
   folderA
      file1
   folderB
      file2
   folderC
      file3

Ten prosty kod załatwił sprawę: (Jestem na Uniksie)

import os
import glob

folders = glob.glob('./path/to/parentdir/*')
for fo in folders:
  file = glob.glob(f'{fo}/*')
  for f in file:
    os.remove(f)

Mam nadzieję że to pomoże.

NicoBar
źródło
1

Rozwiązałem problem rmtree makedirs, dodając time.sleep()między:

if os.path.isdir(folder_location):
    shutil.rmtree(folder_location)

time.sleep(.5)

os.makedirs(folder_location, 0o777)
fizyka
źródło
0

Odpowiedz na ograniczoną, konkretną sytuację: zakładając, że chcesz usunąć pliki podczas utrzymywania drzewa podfolderów, możesz użyć algorytmu rekurencyjnego:

import os

def recursively_remove_files(f):
    if os.path.isfile(f):
        os.unlink(f)
    elif os.path.isdir(f):
        for fi in os.listdir(f):
            recursively_remove_files(os.path.join(f, fi))

recursively_remove_files(my_directory)

Może nieco nie na temat, ale myślę, że wielu uznałoby to za przydatne

fmonegaglia
źródło
Używanie os.walkw sposób pokazany na stackoverflow.com/a/54889532/1709587 jest być może lepszym sposobem na usunięcie wszystkich plików przy jednoczesnym zachowaniu nienaruszonej struktury katalogów.
Mark Amery
-1

Zakładając, temp_dirże zostanie usunięty, użycie polecenia w jednym wierszu osbyłoby:

_ = [os.remove(os.path.join(save_dir,i)) for i in os.listdir(temp_dir)]

Uwaga: jest to tylko jeden linijka do usuwania plików „Nie usuwa katalogów.

Mam nadzieję że to pomoże. Dzięki.

End-2-End
źródło
-1

Użyj metody poniżej, aby usunąć zawartość katalogu, a nie sam katalog:

import os
import shutil

def remove_contents(path):
    for c in os.listdir(path):
        full_path = os.path.join(path, c)
        if os.path.isfile(full_path):
            os.remove(full_path)
        else:
            shutil.rmtree(full_path)
Amir Rezazadeh
źródło
@FabioSpaghetti Negative
Amir Rezazadeh
dziękuję Amir, szukam rozwiązania, które znajdzie określony folder we wszystkich podkatalogach katalogu głównego i usunie zawartość tego folderu
FabioSpaghetti
Nie dodaje to niczego nowego, co nie było jeszcze wyświetlane w zaakceptowanych odpowiedziach przez wiele lat przed opublikowaniem tego.
Mark Amery
-1

najprostszy sposób na usunięcie wszystkich plików w folderze / usunięcie wszystkich plików

import os
files = os.listdir(yourFilePath)
for f in files:
    os.remove(yourFilePath + f)
PyBoss
źródło
Nie działa, jeśli istnieją podkatalogi.
Mark Amery
-3

To powinno załatwić sprawę tylko za pomocą modułu systemu operacyjnego, aby wyświetlić listę, a następnie usunąć!

import os
DIR = os.list('Folder')
for i in range(len(DIR)):
    os.remove('Folder'+chr(92)+i)

Pracował dla mnie, wszelkie problemy daj mi znać!

B. Filer
źródło