Как удалить содержимое папки?

470

Как я могу удалить содержимое локальной папки в Python?

Текущий проект предназначен для Windows, но я бы тоже хотел увидеть * nix.

UnkwnTech
источник
2
для * nix, если честно, я бы просто использовалos.system('rm -rf folder')
Тилак Мэдди

Ответы:

444
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 (folder) в Py3.5 вместо listdir. Синтаксис после этого совсем другой, но довольно простой в реализации; рад опубликовать это, если другие хотят.
Майкл Скотт Катберт
Я получаю предупреждение Pylint с 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 для удаления всех текстовых файлов в каталоге.

Blueicefield
источник
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 - true, ошибки, возникшие в результате неудачного удаления, будут игнорироваться; если false или пропущено, такие ошибки обрабатываются путем вызова обработчика, указанного в onerror, или, если он пропущен, они вызывают исключение.

Oli
источник
270
Это приведет к удалению не только содержимого, но и самой папки. Я не думаю, что это вопрос.
Икер Хименес
3
Я думаю, что это хороший ответ. Почему бы вам просто не удалить содержимое и папку, а затем переделать папку?
cssndrx
42
Потому что новый каталог и старый не будут совпадать. Так что, если программа сидит в каталоге, ожидая чего-то, из-под нее вытащит коврик.
Майк Купер
30
Просто создайте каталог после rmtree. Какos.makedirs(dir)
Юлий Курт
3
@IuliusCurt нет, у меня есть каталог, смонтированный в оперативной памяти, который мне нужно очистить, и, к сожалению, я не могу просто удалить, а затем заново создать его:OSError: [Errno 16] Device or resource busy
Arnaud P
80

Расширяя ответ mhawke, это то, что я реализовал. Он удаляет все содержимое папки, но не саму папку. Протестировано на 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используется для разделения файлов и каталогов, которые должны обрабатываться по-разному. Вы также можете использовать os.listdir, но вам придется проверять, является ли каждая запись вручную или файлом.
Дкаминс
7
Это близко, но и os.walk, и shutil.rmtree являются рекурсивными. os.walk не нужен, поскольку для очистки вам нужны только файлы и каталоги верхнего уровня внутри каталога. Просто используйте оператор if для элементов в os.listdir, чтобы увидеть, является ли каждый из них файлом или каталогом. Затем используйте remove / unlink и rmtree соответственно.
Мэтью Альперт
1
@MatthewAlpert Обратите внимание, что здесь os.walkэто не будет повторяться, потому что он возвращает генератор, который рекурсивно просматривает только подкаталоги, когда вы пытаетесь продвинуть его, и к тому времени, как вы сделали свою первую итерацию этого цикла, подкаталогов нет. осталось посмотреть. По сути, os.walkон используется здесь как альтернативный способ отличить папки верхнего уровня от файлов верхнего уровня; рекурсия не используется, и мы не платим за нее производительность. Это эксцентрично, и я согласен, что предлагаемый вами подход лучше, потому что он более понятен и читабелен.
Марк Амери
47

С помощью rmtree и воссоздание папки может работать, но я столкнулся с ошибками при удалении и немедленном воссоздании папок на сетевых дисках.

Предлагаемое решение с использованием Walk не работает, поскольку оно использует 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)
jgoeders
источник
1
Ваше решение также вызовет ошибку, если есть символическая ссылка на другой каталог.
Blueicefield
@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)) )
fmonegaglia
источник
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» содержит хотя бы одну папку, поскольку unlink работает только для файлов ...
kupsef
14

Примечания: если кто-то проголосовал за мой ответ, у меня есть кое-что объяснить здесь.

  1. Всем нравятся короткие и простые ответы. Однако иногда реальность не так проста.
  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")
Rockallite
источник
Я не понимаю, в каком контексте изменение режима файла имеет смысл. На моем 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(...)должно также работать.
С. Кирби
12
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
@ Rockalite Спасибо. Вы правы. Я обновил пример.
Джейкоб Ван
8

Вам может быть лучше использовать os.walk()для этого.

os.listdir()не отличает файлы от каталогов, и вы быстро столкнетесь с проблемами, пытаясь отсоединить их. Существует хороший пример использования os.walk()рекурсивно удалить каталог здесь , и подсказки о том , как адаптировать его к вашей ситуации.

mhawke
источник
6

Я использовал для решения проблемы следующим образом:

import shutil
import os

shutil.rmtree(dirpath)
os.mkdir(dirpath)
ProfHase85
источник
7
Это имеет радикально отличную семантику от того, что задает вопрос, и не должно рассматриваться как правильный ответ.
фатухоку
1
С уважением, я думаю, что «Удалить содержимое локальной папки» не включает удаление самой папки. Та же проблема, что и в этом ответе , за исключением того, что получено много голосов!
фатухоку
3
Это все равно что ответить на вопрос «Как заставить функцию вернуть число 1 в Python?» с def return_a_one (): launch_some_nukes () возврат 1
фатухоку
2
Конечно, семантика другая: но вы могли бы также рассмотреть это как другой способ взглянуть на проблему. Это решение совершенно справедливо, поскольку оно решает проблему. В вашем примере launch_some_nukes есть различие: 1. Решение короче и проще принятого, и в отличие от приведенного вами ответа оно действительно. 2. эквивалентом 'launch_some_nukes' в этом случае является удаление и воссоздание папки. Разница между старой и новой папками заключается только в номере инода (вероятно, не имеет значения для 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)
silverbullettt
источник
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)
physlexic
источник
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)

Может быть, немного не по теме, но я думаю, что многие найдут это полезным

fmonegaglia
источник
Использование 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 строка для удаления файлов «Не удаляет каталоги.

Надеюсь это поможет. Спасибо.

End-2-End
источник
-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 Негатив
Амир Резазаде
спасибо, Амир, я ищу решение, которое находит определенную папку во всех подкаталогах корневого каталога и удаляет содержимое этой папки
FabioSpaghetti
Это не добавляет ничего нового, что не было показано в принятых ответах за годы до того, как вы опубликовали это.
Марк Амери
-1

самый простой способ удалить все файлы в папке / удалить все файлы

import os
files = os.listdir(yourFilePath)
for f in files:
    os.remove(yourFilePath + f)
PyBoss
источник
Сбой, если есть подкаталоги.
Марк Амери
-3

Это должно сделать трюк, просто используя модуль OS, чтобы вывести список, а затем удалить!

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

Работал на меня, любые проблемы, дайте мне знать!

Б. Филер
источник