在Python中删除除一个子目录以外的目录

在Python中删除除一个子目录以外的目录,python,Python,我有一些目录,我想删除,但其中一个目录有一个子目录,我想保留 例如: 档案 照片 cat.png icon.png 音乐 song.mp3 电影 第一.mp4 我想删除除子目录图片以外的所有内容(目录和子目录) 现在我有这个: def Destroy_Path(path): shutil.rmtree(path, ignore_errors=True) 这里有一个解决方案未经测试 请注意,使用os.walk()可以就地更改dirnames,告诉它不要递归到子目录中,并避免使用会破坏此功

我有一些目录,我想删除,但其中一个目录有一个子目录,我想保留

例如:

档案

照片

cat.png

icon.png

音乐

song.mp3

电影

第一.mp4

我想删除除子目录图片以外的所有内容(目录和子目录)

现在我有这个:

def Destroy_Path(path):
    shutil.rmtree(path, ignore_errors=True)

这里有一个解决方案未经测试

请注意,使用
os.walk()
可以就地更改
dirnames
,告诉它不要递归到子目录中,并避免使用会破坏此功能的
top down=False

当topdown为
True
时,调用者可以就地修改目录名列表 (可能使用
del
或slice赋值)和
walk()
只会重复出现 进入名称保留为dirnames的子目录;这可能是 用于删除搜索,[…] 当自上而下为
False时修改dirnames对漫游行为没有影响,因为在自下而上模式下,dirnames中的目录是在dirpath本身生成之前生成的

有关更多信息,请参阅

另外值得注意的是使用
os.path.samefile()
进行路径比较。这是

这是未经测试的

使用风险自负

说真的,小心点


图片
移动到其他地方,删除所有内容,然后将其移回。您是否接受任何标准的*nix工具,例如
基于查找
的解决方案?@Selcuk移动、删除和移回将不起作用,因为中间目录将同时被删除。可以为每个要保留的文件/文件夹重新创建所需的目录结构,但中间目录的元数据(如权限和修改日期)可能已丢失。这似乎有点过分了。只需定义一个小函数,将您感兴趣的每个文件夹从当前路径移动到临时目录,使用shutil.rmtree,然后将其移回,或者更好的是,打开Nautilus即可。@AlexanderHuszagh moving,删除和向后移动将不起作用,因为中间目录将同时被删除。可以为每个“受保护”项目重新创建所需的目录结构,但这些目录的元数据(如权限和修改日期)将丢失。这是解决复杂、全面问题的一个很好的解决方案。但除非这是一种非常不寻常的情况(比如远程日志,有人需要对dir进行写访问,但不需要读访问;有人需要对父级进行读访问,但不需要写),否则简单性在其他情况下也同样适用。如果他们需要匹配给定的文件名(可能在目录层次结构的任何级别),那么walk方法是很好的。@AlexanderHuszagh您建议的“简单”解决方案实际上并不简单:至少,它必须检查每个异常是否真的存在,将其移动到临时目录,调用
rmtree()。
import os

def gen_dir_paths_except(base_path, exceptions):
    # behave like os.walk(): return nothing if the given path isn't a directory
    if not os.path.isdir(base_path):
        return

    # keep only existing paths in exceptions, so that os.path.samefile() works
    exceptions = list(filter(os.path.exists, exceptions))

    # don't forget the base directory
    if any(os.path.samefile(base_path, x) for x in exceptions):
        return
    yield base_path

    for curr_dirpath, dirnames, filenames in os.walk(base_path):    
        # skip directories mentioned in exceptions
        dirnames_to_skip = []
        for dir_name in dirnames:
            dir_path = os.path.join(curr_dirpath, dir_name)
            if any(os.path.samefile(dir_path, x) for x in exceptions):
                dirnames_to_skip.append(dir_name)
            else:
                yield dir_path
        for dir_name in dirnames_to_skip:
            dirnames.remove(dir_name)

def rmtree_except(path, exceptions):
    # Check that the path is actually a directory. This is needed here
    # because os.walk() will silently return nothing for a non-directory.
    if not os.path.isdir(path):
        if not os.path.exists(path):
            raise OSError("No such directory: " + path)
        else:
            raise OSError("Not a directory: " + path)

    # keep only existing paths in exceptions, so that os.path.samefile() works
    exceptions = list(filter(os.path.exists, exceptions))

    dirs = list(gen_dir_paths_except(path, exceptions))
    # iterate through directories in bottom-up order
    for dir_path in reversed(dirs):
        filenames = [
            x for x in os.listdir(dir_path)
            if not os.path.isdir(os.path.join(dir_path, x))
        ]
        for file_name in filenames:
            # skip files mentioned in exceptions
            file_path = os.path.join(dir_path, file_name)
            if not any(os.path.samefile(file_path, x) for x in exceptions):
                os.remove(file_path)

        try:
            os.rmdir(dir_path)
        except OSError: # directory not empty
            pass # just leave the directory