张银峰的编程课堂

有序删除:先文件后目录

我们看看用程序清理下面这种文件结构时的表现。

CS.GLIMIX.COM
│  001.png
│  format.txt
│  fun.c
│  fun.h
│  main.c
│
├─Debug
│      fun.obj
│      main.obj
│      va.obj
│      vb.obj
│
├─Release
│      main.obj
│      tutorials.exe
│      tutorials.log
│
└─test
       fun.c
       fun.h

glimix.com

目前ccleaner在删除上的逻辑是遇到什么删除什么。如果我们希望先删除文件,然后是文件夹,这就需要先将文件夹名称缓存起来,在删除完当前目录下的全部文件后,再从缓存中取出一个目录,执行文件/文件夹删除逻辑,直到所有的子目录删除完成。这里对文件名称的缓存,是通过一个指针数组来表达。

char *subdirs[BUFSIZ] = { 0 };  // 存储子文件夹名称
int sdidx = 0;                  // 文件夹存储位置索引

在查找文件时,我们可以通过strdup()函数,创建名称字符串副本,然后将它存储到subdirs中。

if (fd.attrib & _A_SUBDIR)
{
    if (strcmp(fd.name, ".") != 0 && strcmp(fd.name, "..") != 0)
    {
        // 保存文件夹名称
        subdirs[sdidx++] = _strdup(fd.name);
    }
}

strdup先使用malloc分配空间然后复制内容,所以要记得使用free释放。

一切就绪后,我们通过遍历subdirs进行递归删除。

for (int i = 0; i < sdidx; i++)
{
    char subdir[BUFSIZ];
    sprintf_s(subdir, BUFSIZ, "%s\\%s", dir, subdirs[i]);

    // 递归遍历子文件夹
    dirctx subctx;
    bool ok = clear_core(subdir, &subctx);

    // 遍历完成 && 移除空文件夹 && 本次在子文件夹查找与删除的文件计数一致
    if (ok && opts.remove_empty_dir && (subctx.found_count == subctx.delete_count))
    {
        // 在当前层删除子文件夹,成功后,文件删除计数加1
        if (_rmdir(subdir) == 0)
        {
            ctx->delete_count += 1;
            ctx->delete_dir_count += 1;
        }
    }

    // 当前层文件计数加1(不能在删除文件夹之前累加,
    // 此时subctx.delete_count统计的仅仅是已删除的文件数量,这当中不包括文件夹计数)
    ctx->found_count += 1;

    // 释放strdup分配的内存
    free(subdirs[i]);
}

现在,我们就可以得到一个整齐的输出了。

glimix.com