Як видалити вміст папки?


468

Як я можу видалити вміст локальної папки в Python?

Поточний проект призначений для Windows, але я також хотів би бачити * nix.


2
для * nix, якщо чесно, я би просто скориставсяos.system('rm -rf folder')
Тілак

Відповіді:


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

4
Якщо ви працюєте з дуже великим каталогом, зокрема мережевим каталогом у Windows, і ви можете керувати середовищем, в якому працює ця програма, можливо, варто використовувати функцію "os.scandir (папка)" Py3.5 замість listdir. Синтаксис після цього зовсім інший, але досить простий у виконанні; радий розмістити його, якщо хочуть інші.
Майкл Скотт Катберт

Я отримую попередження про пілінт із except Exception as e:цим повідомленням W0703: Catching too general exception Exception. Чи є конкретніший виняток для вилову або я повинен його ігнорувати?
Джон Гані

7
@JohnHany, я вважаю, ти хочеш зловити OSError.
MikeB

246

Ви можете просто зробити це:

import os
import glob

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

Звичайно, ви можете використовувати інший фільтр у своєму шляху, наприклад: /YOU/PATH/*.txt для видалення всіх текстових файлів у каталозі.


12
@Blueicefield *не буде перераховувати приховані файли, ми також повинні додатиglob.glob('path/.*)
satoru

5
хоча видалити список файлів, мені здається простіше:import sh; sh.rm(files)
Робін Уінслоу,

2
Хоча import sh; sh.rm(files)це виглядає красивіше, у вас виникають проблеми, якщо в каталозі є більше 1024 файлів.
Євген

235

Ви можете видалити саму папку, а також весь її вміст, використовуючи shutil.rmtree:

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


Видалити ціле дерево каталогів; шлях повинен вказувати на каталог (але не символічне посилання на каталог). Якщо значення ignore_errors є істинним, помилки в результаті невдалого видалення будуть ігноруватися; якщо помилкові чи пропущені, такі помилки обробляються за допомогою виклику обробника, визначеного onerror, або, якщо це пропущено, вони створюють виняток.


270
Це видалить не тільки вміст, але й саму папку. Я не думаю, що це запитання.
Ікер Хіменес

3
Я думаю, що це хороша відповідь. Чому ви просто не видалите вміст і папку, а потім переробите її?
cssndrx

42
Тому що новий каталог і старий не будуть однаковими. Тож якщо в каталозі сидить програма, яка чекає речей, її килимок витягне з-під неї.
Майк Купер

30
Просто відтворіть каталог після rmtree. Likeos.makedirs(dir)
Iulius Curt

3
@IuliusCurt ні, у мене в каталозі встановлений каталог, мені потрібно спорожнити, і, на жаль, я не можу просто видалити, а потім створити його знову:OSError: [Errno 16] Device or resource busy
Arnaud P

80

Розширюючись на відповідь Мауке, це те, що я реалізував. Він видаляє весь вміст папки, але не саму папку. Тестований на Linux з файлами, папками та символічними посиланнями, повинен працювати і в 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))

1
Чому "ходити", а не лише перераховувати вміст папок?
Дон

2
Це правильна відповідь, якщо ви хочете також видалити каталоги. walkвикористовується для розділення файлів dirs і файлів, з якими потрібно по-різному оброблятись. Ви також можете використовувати os.listdir, але вам доведеться перевірити, чи кожен запис є dir або файл вручну.
dkamins

7
Це близько, але і os.walk і shutil.rmtree є рекурсивними. os.walk непотрібний, оскільки для очищення потрібні лише файли та каталоги на верхньому рівні всередині каталогу. Просто скористайтеся оператором if на елементах в os.listdir, щоб побачити, чи кожен є файлом чи каталогом. Потім використовуйте delete / unlink та rmtree відповідно.
Меттью Алперт

1
@MatthewAlpert Зауважте, що os.walkце не повториться тут, оскільки він повертає генератор, який тільки рекурсивно переглядає підкаталоги, коли ви намагаєтесь просунути його, і до того моменту, коли ви зробили першу ітерацію цього циклу, немає підкаталогів. зліва подивитися. По суті, os.walkпросто використовується тут як альтернативний спосіб відрізнити папки верхнього рівня від файлів верхнього рівня; рекурсія не використовується, і ми не сплачуємо за неї продуктивність. Однак це ексцентрично, і я погоджуюсь, що запропонований вами підхід кращий просто тому, що він є більш чітким і зрозумілим.
Марк Амері

47

Використання rmtreeта відтворення папки могло б працювати, але я зіткнувся з помилками при видаленні та негайному відтворенні папок на мережевих накопичувачах.

Запропоноване рішення з використанням ходу не працює, оскільки воно використовується rmtreeдля видалення папок, а потім може спробувати використовувати os.unlinkфайли, які раніше були в цих папках. Це спричиняє помилку.

Опубліковане globрішення також намагатиметься видалити непорожні папки, що спричинить помилки.

Я пропоную вам скористатися:

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)

1
Ваше рішення також призведе до помилки, якщо є симпосилання на інший каталог.
Блудіфілд

@Blueicefield - чи можете ви навести приклад. Я протестував у linux за допомогою файлів і папок, що мають посилання, і досі не міг викликати помилку.
jgoeders

@jgoeders - Якщо є символьне посилання на каталог, os.path.isfile()повернеться False(тому що воно слідує за посиланнями), і ви в кінцевому підсумку дзвоните shutil.rmtree()на символьне посилання, яке підніме OSError("Cannot call rmtree on a symbolic link").
Rockallite

1
@Rockallite зафіксовано чеком на islink
kevinf

1
Також: @kevinf правильно вказати на необхідність islinkперевірки тут, щоб правильно обробляти посилання на каталоги. Я додав таку перевірку до прийнятої відповіді.
Марк Амері

20

Це:

  • видаляє всі символічні посилання
    • мертві посилання
    • посилання на каталоги
    • посилання на файли
  • видаляє підкаталоги
  • не видаляє батьківський каталог

Код:

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

Як і багато інших відповідей, це не намагається коригувати дозволи, щоб увімкнути видалення файлів / каталогів.


15

Як онлайнер:

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

Більш надійним рішенням обліку файлів і каталогів було б (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)) )

1
для великих операцій з використанням генератора може бути частково ефективнішеmap( os.unlink, (os.path.join( mydir,f) for f in os.listdir(mydir)) )
user25064

насправді, намагаючись це використати, зрозумів, що об’єкт карти повинен бути повторений, тому потрібен дзвінок до списку (або щось, що повториться), наприкладlist(map(os.unlink, (os.path.join( mydir,f) for f in os.listdir(mydir))))
user25064,

Перший, включений у відповідь, другий не має для мене сенсу. Чому слід повторювати функцію, відображену на ітерабельному? Карта робить це.
fmonegaglia

1
У Python3, ви повинні обернути mapв list насправді ітерацію. Дивіться http://stackoverflow.com/questions/1303347/getting-a-map-to-return-a-list-in-python-3-x
paulwasit

Ця однозначно не працюватиме, якщо "mydir" містить принаймні одну папку, оскільки від’єднання працює лише для файлів ...
kupsef

14

Примітки: якщо хтось проголосував за мою відповідь, я маю щось тут пояснити.

  1. Всім подобаються короткі «n» прості відповіді. Однак іноді реальність не така проста.
  2. Назад до моєї відповіді. Я знаю, що shutil.rmtree()може бути використане для видалення дерева директорій. Я багато разів використовував її у власних проектах. Але ви повинні усвідомити, що сам каталог також буде видалений користувачемshutil.rmtree() . Хоча це може бути прийнятним для деяких, це неправдива відповідь на видалення вмісту папки (без побічних ефектів) .
  3. Я покажу вам приклад побічних ефектів. Припустимо, у вас є каталог із налаштованими бітами власника та режиму, де багато вмісту. Потім ви видалите його shutil.rmtree()і відновіть os.mkdir(). І ви отримаєте порожній каталог із типовими (успадкованими) власниками та бітами режиму. Незважаючи на те, що ви можете мати привілей видаляти вміст і навіть каталог, ви, можливо, не зможете повернути початкового власника та бітів режиму в каталозі (наприклад, ви не суперпользователь).
  4. Нарешті, наберіться терпіння і прочитайте код . Він довгий і потворний (на виду), але виявився надійним та ефективним (у використанні).

Ось довге і потворне, але надійне та ефективне рішення.

Він вирішує кілька проблем, які не вирішуються іншими відповідачами:

  • Він правильно обробляє символічні посилання, включаючи не викликає shutil.rmtree()символічне посилання (що пройде os.path.isdir()тест, якщо воно посилається на каталог; навіть результат os.walk()містить символічні пов'язані каталоги).
  • Він прекрасно обробляє файли, доступні лише для читання.

Ось код (єдиною корисною функцією є 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")

Я не розумію, в якому контексті зміна режиму файлу має сенс. На моєму Mac, os.remove, в відміну від rmутиліти, радий видалити файли тільки для читання до тих пір , поки у вас є їх. Тим часом, якщо ви не володієте файлом, до якого ви маєте доступ лише для читання, ви не можете його видалити або змінити його дозволи. Я не знаю жодної ситуації в будь-якій системі, де ви не зможете видалити файл, який читається лише з os.removeтим, що ще не зможете змінити його дозволи. Крім того, ви використовуєте lchmod, що не існує ні на моєму Mac, ні в Windows відповідно до його документів. Для якої платформи призначений цей код ?!
Марк Амері

14

Я здивований, що ніхто не згадав, що дивовижно pathlibробити цю роботу.

Якщо ви хочете видалити лише файли в каталозі, це може бути oneliner

from pathlib import Path

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

Для рекурсивного видалення каталогів ви можете написати щось подібне:

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)

1
.iterdir()замість .glob(...)також повинні працювати.
С. Кірбі

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]

У попередньому коментарі також згадується використання os.scandir в Python 3.5+. Наприклад:

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)

1
os.path.isdir()не є дійсним способом розрізнити звичайний каталог та символічне посилання. Виклик shutil.rmtree()на символічному посиланні призведе до OSErrorвинятку.
Rockallite

@Rockallite Дякую Ти правий. Я оновив приклад.
Якоб Ван

8

Можливо, вам буде краще використовувати os.walk()для цього.

os.listdir()не відрізняє файли від каталогів, і ви швидко потрапите в проблеми, намагаючись від’єднати їх. Існує хороший приклад використання os.walk()рекурсивно видалити каталог тут , і підказки про те , як адаптувати його до вашої ситуації.


6

Я вирішував проблему таким чином:

import shutil
import os

shutil.rmtree(dirpath)
os.mkdir(dirpath)

7
Це радикально відрізняється семантикою від того, що задається питанням, і його не слід вважати правильною відповіддю.
fatuhoku

1
З повагою я думаю, що "Видалити вміст локальної папки" не передбачає видалення самої папки. Така ж проблема, як і ця відповідь , за винятком того, що за один отримано багато оновлень!
fatuhoku

3
Це як відповісти на запитання "Як у мене функція повертає число 1 в Python?" з def return_a_one (): start_some_nukes () return 1
fatuhoku

2
Звичайно, семантика різна: але ви також можете розглянути це як інший спосіб розглянути проблему. Це рішення цілком справедливо, оскільки вирішує проблему. У вашому прикладі "start_some_nukes" є різниця: 1. Рішення коротше і простіше, ніж прийняте, і проти того, щоб ви відповіли, що ви цитували, воно справедливе. 2. еквівалент 'start_some_nukes' у цьому випадку видаляє та відтворює папку. Різниця між старою і новою папкою - це лише номер inode (мабуть, не має значення для OP)
ProfHase85

2
Це швидше знесення хмарочоса і відновлення одного абсолютно такого ж розміру;)
ProfHase85

5

Ще одне рішення:

import sh
sh.rm(sh.glob('/path/to/folder/*'))

1
Зауважте, що shвін не є частиною стандартної бібліотеки і потребує встановлення з PyPI, перш ніж ви зможете використовувати її. Крім того, оскільки це фактично викликає rmпідпроцес, воно не працюватиме в Windows там, де rmйого немає. Також буде створено виняток, якщо папка містить будь-які підкаталоги.
Марк

5

Я знаю, що це стара тема, але я знайшов щось цікаве з офіційного сайту python. Просто для спільного використання іншої ідеї для видалення всього вмісту в каталозі. Оскільки у мене є проблеми з авторизацією при використанні shutil.rmtree (), і я не хочу видаляти каталог і відтворювати його. Оригінал адреси - http://docs.python.org/2/library/os.html#os.walk . Сподіваюся, що це могло б комусь допомогти.

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

4

Щоб видалити всі файли всередині каталогу, а також його підкаталоги, не видаляючи самі папки, просто зробіть це:

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

3

Якщо ви використовуєте систему * nix, чому б не використовувати системну команду?

import os
path = 'folder/to/clean'
os.system('rm -rf %s/*' % path)

3
Тому що, як сказано в питанні, "Поточний проект для Windows"
сокс з Монікою

3

Досить інтуїтивно зрозумілий спосіб:

import shutil, os


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


remove_folder_contents('/path/to/folder')

3

Ну, я думаю, цей код працює. Він не видалить папку, і ви можете використовувати цей код для видалення файлів, що мають певне розширення.

import os
import glob

files = glob.glob(r'path/*')
for items in files:
    os.remove(items)

3

Мені довелося видалити файли з 3-х окремих папок всередині одного батьківського каталогу:

directory
   folderA
      file1
   folderB
      file2
   folderC
      file3

Цей простий код зробив для мене хитрість: (я в Unix)

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)

Сподіваюсь, це допомагає.


1

Я вирішив проблему rmtree makedirs, додавши time.sleep()між собою:

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

time.sleep(.5)

os.makedirs(folder_location, 0o777)

0

Відповідь на обмежену, конкретну ситуацію: припускаючи, що ви хочете видалити файли під час збереження дерева дерев підпапок, ви можете використовувати рекурсивний алгоритм:

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)

Можливо, трохи поза темою, але я думаю, що багато хто вважає це корисним


Використання os.walkспособу, показаного на stackoverflow.com/a/54889532/1709587 , можливо, приємніший спосіб видалення всіх файлів, залишаючи недоторканою структуру каталогу.
Марк Амері

-1

Якщо припустити, temp_dirщо буде видалено, командою для одного рядка osбуде:

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

Примітка. Це лише 1-вкладиш для видалення файлів "Не видаляє каталоги.

Сподіваюсь, це допомагає. Дякую.


-1

Використовуйте метод нижче, щоб видалити вміст каталогу, а не сам каталог:

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)

@FabioSpaghetti Negative
Amir

дякую, Аміре, я шукаю рішення, яке знаходить певну папку у всіх підкаталогах кореневого каталогу та видаляє вміст цієї папки
FabioSpaghetti

Це не додає нічого нового, що вже не було показано у прийнятій відповіді за роки до опублікування цього повідомлення.
Марк Амері

-1

найпростіший спосіб видалити всі файли в папці / видалити всі файли

import os
files = os.listdir(yourFilePath)
for f in files:
    os.remove(yourFilePath + f)

Помилка, якщо є підкаталоги.
Марк Амері

-3

Для цього слід виконати трюк, просто скориставшись модулем ОС, а потім видалити!

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

Працювали для мене, будь-які проблеми дайте мені знати!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.