簡體   English   中英

如何刪除/刪除非空文件夾?

[英]How do I remove/delete a folder that is not empty?

當我嘗試刪除非空文件夾時,出現“訪問被拒絕”錯誤。 我在嘗試中使用了以下命令: os.remove("/folder_name")

刪除/刪除非空文件夾/目錄的最有效方法是什么?

import shutil

shutil.rmtree('/folder_name')

標准庫參考: shutil.rmtree

按照設計, rmtree在包含只讀文件的文件夾樹上失敗。 如果您希望刪除文件夾而不管它是否包含只讀文件,然后使用

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

來自os.walk()的 python 文檔

# 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))
import shutil
shutil.rmtree(dest, ignore_errors=True)

從 python 3.4 你可以使用:

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 the dir content but not the dir itself, remove this line

其中pthpathlib.Path實例。 不錯,但可能不是最快的。

來自docs.python.org

此示例說明如何在 Windows 上刪除目錄樹,其中某些文件設置了只讀位。 它使用 onerror 回調清除只讀位並重新嘗試刪除。 任何后續失敗都會傳播。

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

如果設置了ignore_errors,則忽略錯誤; 否則,如果設置了 onerror,則調用它來處理帶有參數(func、path、exc_info)的錯誤,其中 func 是 os.listdir、os.remove 或 os.rmdir; path 是導致它失敗的函數的參數; exc_info 是 sys.exc_info() 返回的元組。 如果 ignore_errors 為 false 且 onerror 為 None,則會引發異常。在此處輸入代碼

根據 kkubasik 的回答,在刪除之前檢查文件夾是否存在,更健壯

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

我想添加一個“純路徑庫”方法:

from pathlib import Path
from typing import Union

def del_dir(target: Union[Path, str], only_if_empty: bool = False):
    """
    Delete a given directory and its subdirectories.

    :param target: The directory to delete
    :param only_if_empty: Raise RuntimeError if any file is found in the tree
    """
    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()

這依賴於Path是可排序的,較長的路徑總是排在較短的路徑之后,就像str一樣。 因此,目錄將位於文件之前。 如果我們顛倒排序,文件將出現在它們各自的容器之前,所以我們可以簡單地一次一個地取消鏈接/ rmdir它們。

好處:

  • 它不依賴於外部二進制文件:一切都使用 Python 的電池模塊(Python >= 3.6)
    • 這意味着它不需要重復啟動一個新的子進程來進行取消鏈接
  • 它非常快速和簡單; 您不必實現自己的遞歸
  • 它是跨平台的(至少,這是pathlib在 Python 3.6 中所承諾的;上面沒有說明不能在 Windows 上運行的操作)
  • 如果需要,可以進行非常精細的日志記錄,例如,在每次刪除發生時記錄它。

只需一些 python 3.5 選項即可完成上述答案。 (我很想在這里找到它們)。

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

如果為空則刪除文件夾

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

如果文件夾包含此文件,則也刪除該文件夾

    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)

如果文件夾僅包含 .srt 或 .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")

如果文件夾大小小於 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")

如果您確定要刪除整個目錄樹,並且對目錄的內容不再感興趣,那么抓取整個目錄樹是愚蠢的……只需從 python 調用本機操作系統命令即可。 它將更快、更高效且內存消耗更少。

RMDIR c:\blah /s /q 

或 *nix

rm -rf /home/whatever 

在 python 中,代碼看起來像..

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

十年后,使用 Python 3.7 和 Linux 仍然有不同的方法可以做到這一點:

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

本質上,它使用 Python 的 subprocess 模塊來運行 bash 腳本$ rm -rf '/path/to/your/dir ,就好像您使用終端來完成相同的任務一樣。 它不是完全的 Python,但它完成了它。

我包含pathlib.Path示例的原因是因為根據我的經驗,它在處理許多變化的路徑時非常有用。 導入pathlib.Path模塊並將最終結果轉換為字符串的額外步驟對我來說通常會降低開發時間的成本。 如果Path.rmdir()帶有一個 arg 選項來顯式處理非空目錄,那將會很方便。

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)

如果你不想使用shutil模塊,你可以只使用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

刪除一個文件夾,即使它可能不存在(避免Charles Chow 的回答中的競爭條件)但在其他事情出錯時仍然有錯誤(例如權限問題、磁盤讀取錯誤、文件不是目錄)

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

Python 2.7 代碼幾乎相同:

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)

對於 os.walk,我會提出由 3 個單行 Python 調用組成的解決方案:

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

第一個腳本 chmod 的所有子目錄,第二個腳本 chmod 的所有文件。 然后第三個腳本毫無障礙地刪除所有內容。

我已經在 J​​enkins 作業中通過“Shell 腳本”對此進行了測試(我不想將新的 Python 腳本存儲到 SCM 中,這就是搜索單行解決方案的原因),它適用於 Linux 和 Windows。

對於 Windows,如果目錄不為空,並且您有只讀文件或出現類似錯誤

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

試試這個, os.system('rmdir /S /Q "{}"'.format(directory))

它等效於 Linux/Mac 中的rm -rf

基於遞歸的純pathlib解決方案:

from pathlib import Path

def remove_path(path: Path):
    if path.is_file() or path.is_symlink():
        path.unlink()
        return
    for p in path.iterdir():
        remove_path(p)
    path.rmdir()

支持 Windows 和符號鏈接

為簡單起見,您可以使用 os.system 命令:

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

很明顯,它實際上調用了系統終端來完成這個任務。

我找到了一種非常簡單的方法來刪除WINDOWS OS上的任何文件夾(甚至不是空的)或文件。

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

在我的情況下,刪除的唯一方法是使用所有可能性,因為我的代碼應該由 cmd.exe 或 powershell.exe 運行。 如果是您的情況,只需使用此代碼創建一個函數即可:

        #!/usr/bin/env python3

        import shutil
        from os import path, system
        import sys

        # Try to delete the folder ---------------------------------------------
        if (path.isdir(folder)):
            shutil.rmtree(folder, ignore_errors=True)

        if (path.isdir(folder)):
            try:
                system("rd -r {0}".format(folder))
            except Exception as e:
                print("WARN: Failed to delete => {0}".format(e),file=sys.stderr)

        if (path.isdir(self.backup_folder_wrk)):
            try:
                system("rd /s /q {0}".format(folder))
            except Exception as e:
                print("WARN: Failed to delete => {0}".format(e),file=sys.stderr)

        if (path.isdir(folder)):
            print("WARN: Failed to delete {0}".format(folder),file=sys.stderr)
        # -------------------------------------------------------------------------------------

您可以嘗試以下代碼來刪除文件或文件夾,無論它們是空的還是非空的。

import shutil
import os

directory = "path/to/the/root/folder"
files_in_directory = os.listdir(directory)

for file in files_in_directory:
    try:
        path_to_file_or_folder = os.path.join(directory, file)
        shutil.rmtree(path_to_file_or_folder)
    except:
        os.unlink(path_to_file_or_folder)

它有助於刪除包含所有文件和文件夾的目錄

import os


def rrmdir(path):
    for entry in os.scandir(path):
        if entry.is_dir():
            rrmdir(entry)
        else:
            os.remove(entry)
    os.rmdir(path)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM