Làm cách nào để xóa / xóa thư mục không trống?


847

Tôi nhận được lỗi 'truy cập bị từ chối' khi tôi cố xóa một thư mục không trống. Tôi đã sử dụng lệnh sau trong nỗ lực của mình : os.remove("/folder_name").

Cách hiệu quả nhất để xóa / xóa thư mục / thư mục không trống là gì?


32
Cũng lưu ý rằng ngay cả khi thư mục trống, os.remove sẽ lại thất bại, vì chức năng chính xác là os.rmdir.
tzot

Câu trả lời:


1349
import shutil

shutil.rmtree('/folder_name')

Tài liệu tham khảo thư viện chuẩn: shutil.rmtree .

Theo thiết kế, rmtreethất bại trên cây thư mục chứa các tệp chỉ đọc. Nếu bạn muốn thư mục bị xóa bất kể nó có chứa các tệp chỉ đọc hay không, thì hãy sử dụng

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

73
Lưu ý rằng rmtreesẽ thất bại nếu có các tệp chỉ đọc: stackoverflow.com/questions/2656322/NH
Sridhar Ratnakumar

9
Điều này không hiệu quả với tôi: TracBack (cuộc gọi gần đây nhất): Tệp "foo.py", dòng 31, trong <module> shutil.rmtree (thistestdir) Tệp "/usr/lib/python2.6/shutil.py ", dòng 225, trong rmtree onerror (os.rmdir, path, sys.exc_info ()) Tệp" /usr/lib/python2.6/shutil.py ", dòng 223, trong rmtree os.rmdir (path) OSError: [Errno 90] Thư mục không trống: '/ path / to / rmtree'
Clayton Hughes

4
Clayton: trong tất cả khả năng, một tệp được thêm đồng thời trong khi rmtree đang bận xóa công cụ, "rm -rf" sẽ thất bại như vậy.
ddaa

14
Bất cứ ai cũng biết tại sao chức năng này không có trong gói os? Có vẻ như os.rmdir khá vô dụng. Bất kỳ lý lẽ tốt cho lý do tại sao nó thực hiện theo cách này?
Malcolm

21
@Malcolm Gói là một trình bao bọc cho các chức năng của hệ điều hành. Trên hệ thống POSIX, rmdir sẽ thất bại nếu thư mục không trống. UbuntuWindows là những ví dụ phổ biến về tuân thủ POSIX về mặt này.
Iain Samuel McLean Elder

138

Từ tài liệu python trên 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))

1
Chà, có lẽ tôi đã sai khi hạ cấp. Nhưng tôi có thể, ngay bây giờ tôi nghĩ nó đúng.
ddaa

3
@ddaa: Mặc dù sử dụng shutil chắc chắn là cách dễ nhất, nhưng chắc chắn không có gì bất thường về giải pháp này. Tôi sẽ không đưa ra câu trả lời này, nhưng tôi chỉ có thời gian này để hủy bỏ downvote của bạn :)
Jeremy Cantrell

7
Mã chính nó là pythonic. Sử dụng nó thay vì shutil.rmtree trong một chương trình thực sự sẽ là không hợp lý: đó sẽ là bỏ qua "một cách rõ ràng để làm điều đó". Dù sao, đây là ngữ nghĩa, loại bỏ downmod.
ddaa

2
@ddaa Có phải unpythonic muốn đăng nhập mọi tập tin hoặc thư mục bị xóa không? Tôi không chắc chắn làm thế nào để làm điều đó với shutil.rmtree?
Jonathan Komar

4
@ddaa Đó là thức ăn cho ý nghĩ tức là hùng biện. Tôi biết tôi đang làm gì. Tôi chỉ nghĩ rằng bạn có thể muốn xem xét lại "cách làm rõ ràng" bằng cách cung cấp một lý do tại sao shutil.rmtree có thể không đúng "phù hợp".
Jonathan Komar

112
import shutil
shutil.rmtree(dest, ignore_errors=True)

1
Đây là câu trả lời chính xác. Trong hệ thống của tôi, mặc dù tôi đặt mọi thứ trong thư mục cụ thể thành ghi-đọc, tôi vẫn gặp lỗi khi cố xóa. ignore_errors=Truegiải quyết vấn đề
Aventinus

3
Trong câu trả lời của tôi, onerrortham số được sử dụng thay vì ignore_errors. Bằng cách này, các tệp chỉ đọc sẽ bị xóa thay vì bỏ qua.
Dave Chandler

Có, điều này sẽ không xóa các tập tin bị lỗi. Vì vậy, về cơ bản toàn bộ rmtree()phương pháp được bỏ qua.
Juha Untinen

2
Đây phải là một chỉnh sửa nhỏ cho câu trả lời được chấp nhận 6 năm trước đó, thay vì một câu trả lời mới. Tôi sẽ làm điều này bây giờ.
Jean-François Corbett

22

từ python 3,4 bạn có thể sử dụng:

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

nơi pthlà một pathlib.Pathví dụ. Đẹp, nhưng có thể không phải là nhanh nhất.


10

Từ docs.python.org :

Ví dụ này cho thấy cách xóa cây thư mục trên Windows trong đó một số tệp có tập bit chỉ đọc. Nó sử dụng hàm gọi lại onerror để xóa bit chỉ đọc và đánh dấu lại loại bỏ. Bất kỳ thất bại tiếp theo sẽ tuyên truyền.

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)

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) 

Nếu ign_errors được đặt, lỗi sẽ bị bỏ qua; mặt khác, nếu onerror được đặt, nó được gọi để xử lý lỗi với các đối số (func, path, exc_info) trong đó func là os.listdir, os.remove hoặc os.rmdir; đường dẫn là đối số của hàm đó khiến nó bị lỗi; và exc_info là một tuple được trả về bởi sys.exc_info (). Nếu ign_errors là sai và onerror là Không có, một ngoại lệ được đưa ra. Mã trung tâm ở đây


Theo các tài liệu , Ngoại lệ được đưa ra bởi onerror sẽ không bị bắt vì vậy tôi không chắc mã tăng nhập của bạn ở đây có nghĩa gì.
kmarsh

-1. Điều này dường như quá phức tạp so với câu trả lời của Dave Chandler. Ngoài ra, nếu chúng tôi muốn xóa chỉ đọc, chúng tôi không cần phải thực hiện các tệp.
idbrii

7

Dựa trên câu trả lời của kkubasik, kiểm tra xem thư mục có tồn tại trước khi xóa không, mạnh mẽ hơn

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

6
điều này giới thiệu một điều kiện cuộc đua có thể
Corey Goldberg

1
theo hầu hết các pythonic-way-to-xóa-a-file-mà-có thể không tồn tại , tốt hơn là tryxóa và xử lý excepthơn gọi exists()trước
TT-- 2/218

6

nếu bạn chắc chắn rằng bạn muốn xóa toàn bộ cây dir và không quan tâm nhiều hơn đến nội dung của dir, thì việc thu thập dữ liệu cho toàn bộ cây dir là ngu ngốc ... chỉ cần gọi lệnh OS gốc từ python để làm điều đó. Nó sẽ nhanh hơn, hiệu quả và ít tiêu thụ bộ nhớ hơn.

RMDIR c:\blah /s /q 

hoặc * nix

rm -rf /home/whatever 

Trong python, mã sẽ trông như ..

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

33
-1. Toàn bộ quan điểm của việc sử dụng shutil.rmdirlà để cách ly bạn khỏi loại hệ điều hành.
mtrw

3
Tôi hiểu khái niệm này, nhưng khi một người nhận thức rõ về thực tế rằng anh ta muốn xóa hoàn toàn thư mục, vậy thì điểm thu thập dữ liệu của toàn bộ cây tập tin là gì? shutil.rmdir đặc biệt gọi os.listdir (), os.path.islink (), v.v. .. một số kiểm tra không thực sự cần thiết, vì tất cả cần thiết là bỏ liên kết nút hệ thống tệp. Bên cạnh một số hệ thống xây dựng, như MSWindows để phát triển MSAuto / WinCE, thì shtuil.rmdir sẽ thất bại hầu như luôn luôn, vì phát triển dựa trên lô MSAuto khóa một số tệp xây dựng wierd khi thoát không thành công và chỉ rmdir / S / Q hoặc khởi động lại là hữu ích họ
PM

2
vâng, chỉ cần rm gần với kernel hơn, sử dụng ít thời gian, bộ nhớ và cpu ..... và như tôi đã nói, lý do để tôi sử dụng phương pháp này là do các khóa bị bỏ lại bởi các tập lệnh xây dựng hàng loạt MSAuto ...
PM

3
Có, nhưng việc sử dụng shutil làm cho mã đa nền tảng và trừu tượng hóa đi các chi tiết nền tảng.
xshoppyx

2
Tôi không nghĩ câu trả lời này nên được bình chọn dưới 1 vì nó cung cấp một tài liệu tham khảo rất hay cho một tác phẩm xung quanh cho một số tình huống mà người đọc có thể quan tâm. Tôi thích có nhiều phương pháp được đăng theo thứ tự. Vì vậy, mặc dù tôi không cần sử dụng nhưng bây giờ tôi biết nó có thể được thực hiện và làm thế nào.
kmcguire

5

Chỉ cần một số tùy chọn python 3.5 để hoàn thành các câu trả lời ở trên. (Tôi rất thích tìm thấy chúng ở đây).

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

Xóa thư mục nếu trống

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

Xóa thư mục nếu nó chứa tập tin này

    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)

xóa thư mục nếu nó chỉ chứa tệp .srt hoặc .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")

Xóa thư mục nếu kích thước của nó nhỏ hơn 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")

4
Vui lòng sửa lỗi thụt lề và mãif files[0]== "desktop.ini" or:
Mr_and_Mrs_D

5

Tôi muốn thêm một cách tiếp cận "thuần túy 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()

Điều này phụ thuộc vào thực tế Pathlà có trật tự, và các đường dẫn dài hơn sẽ luôn sắp xếp sau các đường dẫn ngắn hơn, giống như str. Do đó, thư mục sẽ đến trước khi tập tin. Nếu chúng ta đảo ngược sắp xếp, các tệp sẽ xuất hiện trước các thùng chứa tương ứng của chúng, vì vậy chúng ta có thể chỉ cần hủy liên kết / rmdir từng cái một với một lần.

Những lợi ích:

  • Nó KHÔNG dựa vào các nhị phân bên ngoài: mọi thứ đều sử dụng các mô-đun bao gồm pin của Python (Python> = 3.6)
  • Nó nhanh và tiết kiệm bộ nhớ: Không có ngăn xếp đệ quy, không cần bắt đầu một quy trình con
  • Đó là nền tảng chéo (ít nhất, đó là những gì pathlibhứa hẹn trong Python 3.6; không có thao tác nào nêu trên không chạy trên Windows)
  • Nếu cần, người ta có thể thực hiện ghi nhật ký rất chi tiết, ví dụ: ghi nhật ký mỗi lần xóa khi nó xảy ra.

bạn có thể cung cấp một ví dụ sử dụng, ví dụ. del_dir (Đường dẫn ())? Cảm ơn
lcapra

@lcapra Đơn giản chỉ cần gọi nó với thư mục để xóa như là đối số đầu tiên.
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)

Tuyệt vời để tạo tập lệnh đặt tập tin vào quarenteen trước khi loại bỏ chúng một cách mù quáng.
racribeiro

3

Nếu bạn không muốn sử dụng shutilmô-đun, bạn chỉ có thể sử dụng osmô-đun.

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

2
os.removekhông thể xóa thư mục vì vậy điều này sẽ tăng OsErrornếu directoryToRemovechứa thư mục con.
Eponymous

#pronetoraceconditions
kapad

3

Mười năm sau và sử dụng Python 3.7 và Linux, vẫn có nhiều cách khác nhau để làm điều này:

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

Về cơ bản, nó sử dụng mô đun quy trình con của Python để chạy tập lệnh bash $ rm -rf '/path/to/your/dirnhư thể bạn đang sử dụng thiết bị đầu cuối để thực hiện cùng một nhiệm vụ. Nó không hoàn toàn là Python, nhưng nó đã được thực hiện.

Lý do tôi đưa vào pathlib.Pathví dụ là vì theo kinh nghiệm của tôi, nó rất hữu ích khi xử lý nhiều đường dẫn thay đổi. Các bước bổ sung của việc nhập pathlib.Pathmô-đun và chuyển đổi kết quả cuối cùng thành chuỗi thường là chi phí thấp hơn đối với tôi trong thời gian phát triển. Sẽ thuận tiện nếu Path.rmdir()đi kèm với một tùy chọn arg để xử lý rõ ràng các thư mục không trống.


Tôi cũng chuyển sang cách tiếp cận này, vì tôi gặp vấn đề với rmtreevà các thư mục ẩn như thế nào .vscode. Thư mục này được phát hiện dưới dạng tệp văn bản và lỗi cho tôi biết rằng tệp này đã busyvà không thể xóa được.
Daniel Eisenreich

2

Để xóa một thư mục ngay cả khi nó không tồn tại (tránh điều kiện cuộc đua trong câu trả lời của Charles Chow ) nhưng vẫn có lỗi khi các sự cố khác xảy ra (ví dụ: sự cố về quyền, lỗi đọc đĩa, tệp không phải là thư mục)

Đối với 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)

Mã Python 2.7 gần như giống nhau:

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

Với os.walk tôi sẽ đề xuất giải pháp bao gồm 3 lệnh gọi Python một lớp:

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

Tập lệnh đầu tiên chmod là tất cả các thư mục con, tập lệnh thứ hai chmod là tất cả các tập tin. Sau đó, kịch bản thứ ba loại bỏ mọi thứ mà không có trở ngại.

Tôi đã thử nghiệm điều này từ "Shell Script" trong công việc Jenkins (Tôi không muốn lưu trữ tập lệnh Python mới vào SCM, đó là lý do tại sao tìm kiếm giải pháp một dòng) và nó hoạt động cho Linux và Windows.


Với pathlib, bạn có thể kết hợp hai bước đầu tiên thành một:[p.chmod(0o666) for p in pathlib.Path(_path_).glob("**/*")]
pepoluan

0

Bạn có thể sử dụng lệnh os.system để đơn giản:

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

Rõ ràng, nó thực sự gọi thiết bị đầu cuối hệ thống để thực hiện nhiệm vụ này.


19
Xin lỗi, đây là Unpythonic và nền tảng phụ thuộc.
Ami Tavory

0

Tôi đã tìm thấy một cách rất dễ dàng để xóa bất kỳ thư mục nào (Thậm chí KHÔNG rỗng) hoặc tệp trên WINDOWS OS .

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

0

Đối với Windows, nếu thư mục không trống và bạn có các tệp chỉ đọc hoặc bạn gặp lỗi như

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

Thử cái này, os.system('rmdir /S /Q "{}"'.format(directory))

Nó tương đương với rm -rfLinux / Mac.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.