在C或C++中以编程方式删除非空目录

avd*_*avd 48 c c++

如何在C或C++中删除非空目录?有什么功能吗?rmdir只删除空目录.请提供一种不使用任何外部库的方法.

还告诉我如何删除C或C++中的文件?

asv*_*kau 29

您希望编写一个函数(递归函数最简单,但很容易用尽深层目录上的堆栈空间),它将枚举目录的子代.如果您发现某个孩子是一个目录,那么您可以对此进行推算.否则,您删除里面的文件.完成后,目录为空,您可以通过系统调用将其删除.

枚举在Unix上的目录,你可以使用opendir,readdirclosedir.要删除您rmdir()在空目录(即功能结束时,删除子项后)和unlink()文件上的使用.请注意,在许多系统上d_type,struct dirent不支持成员; 在这些平台上,您必须使用stat()S_ISDIR(stat.st_mode)确定给定路径是否是目录.

在Windows上,您将使用FindFirstFile()/ FindNextFile()枚举RemoveDirectory()空目录并DeleteFile()删除文件.

这是一个可能适用于Unix的示例(完全未经测试):

int remove_directory(const char *path)
{
   DIR *d = opendir(path);
   size_t path_len = strlen(path);
   int r = -1;

   if (d)
   {
      struct dirent *p;

      r = 0;

      while (!r && (p=readdir(d)))
      {
          int r2 = -1;
          char *buf;
          size_t len;

          /* Skip the names "." and ".." as we don't want to recurse on them. */
          if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, ".."))
          {
             continue;
          }

          len = path_len + strlen(p->d_name) + 2; 
          buf = malloc(len);

          if (buf)
          {
             struct stat statbuf;

             snprintf(buf, len, "%s/%s", path, p->d_name);

             if (!stat(buf, &statbuf))
             {
                if (S_ISDIR(statbuf.st_mode))
                {
                   r2 = remove_directory(buf);
                }
                else
                {
                   r2 = unlink(buf);
                }
             }

             free(buf);
          }

          r = r2;
      }

      closedir(d);
   }

   if (!r)
   {
      r = rmdir(path);
   }

   return r;
}
Run Code Online (Sandbox Code Playgroud)

  • 我第一次这样做,我没有检查"..".是的,结果是程序将目录一直改为c:,然后从那里开始删除!"幸运的是,它发生在工作中.:) (7认同)
  • @Viz你想要dirent.h (2认同)

And*_*son 15

许多类似unix的系统(Linux,BSD和OS X至少)都具有fts目录遍历功能.要递归删除目录,只需执行深度优先遍历(不遵循符号链接)并删除每个访问过的文件.

int recursive_delete(const char *dir)
{
    int ret = 0;
    FTS *ftsp = NULL;
    FTSENT *curr;

    // Cast needed (in C) because fts_open() takes a "char * const *", instead
    // of a "const char * const *", which is only allowed in C++. fts_open()
    // does not modify the argument.
    char *files[] = { (char *) dir, NULL };

    // FTS_NOCHDIR  - Avoid changing cwd, which could cause unexpected behavior
    //                in multithreaded programs
    // FTS_PHYSICAL - Don't follow symlinks. Prevents deletion of files outside
    //                of the specified directory
    // FTS_XDEV     - Don't cross filesystem boundaries
    ftsp = fts_open(files, FTS_NOCHDIR | FTS_PHYSICAL | FTS_XDEV, NULL);
    if (!ftsp) {
        fprintf(stderr, "%s: fts_open failed: %s\n", dir, strerror(errno));
        ret = -1;
        goto finish;
    }

    while ((curr = fts_read(ftsp))) {
        switch (curr->fts_info) {
        case FTS_NS:
        case FTS_DNR:
        case FTS_ERR:
            fprintf(stderr, "%s: fts_read error: %s\n",
                    curr->fts_accpath, strerror(curr->fts_errno));
            break;

        case FTS_DC:
        case FTS_DOT:
        case FTS_NSOK:
            // Not reached unless FTS_LOGICAL, FTS_SEEDOT, or FTS_NOSTAT were
            // passed to fts_open()
            break;

        case FTS_D:
            // Do nothing. Need depth-first search, so directories are deleted
            // in FTS_DP
            break;

        case FTS_DP:
        case FTS_F:
        case FTS_SL:
        case FTS_SLNONE:
        case FTS_DEFAULT:
            if (remove(curr->fts_accpath) < 0) {
                fprintf(stderr, "%s: Failed to remove: %s\n",
                        curr->fts_path, strerror(errno));
                ret = -1;
            }
            break;
        }
    }

finish:
    if (ftsp) {
        fts_close(ftsp);
    }

    return ret;
}
Run Code Online (Sandbox Code Playgroud)

  • 非常好的示例代码和解释 - 这应该是接受的答案. (2认同)

Man*_*uel 14

最简单的方法是使用Boost.Filesystem库的remove_all函数.此外,生成的代码将是可移植的.

如果你想为Unix(rmdir)或Windows(RemoveDirectory)编写特定的东西,那么你必须编写一个递归删除子文件和子文件夹的函数.

编辑

看起来这个问题已经被问到了,事实上有人已经推荐了Boost的remove_all.所以请不要赞成我的回答.

  • brb在我的virtualbox DOS上下载Boost.Filesystem库,以便在我的turbo c编译器上使用. (4认同)

mar*_*ril 13

如果您使用的是POSIX兼容的操作系统,则可以使用nftw()文件树遍历并删除(删除文件或目录).如果您使用的是C++并且您的项目使用了boost,那么使用Manuel建议的Boost.Filesystem并不是一个坏主意.

在下面的代码示例中,我决定不遍历符号链接和挂载点(只是为了避免重大删除:)):

#include <stdio.h>
#include <stdlib.h>
#include <ftw.h>

static int rmFiles(const char *pathname, const struct stat *sbuf, int type, struct FTW *ftwb)
{
    if(remove(pathname) < 0)
    {
        perror("ERROR: remove");
        return -1;
    }
    return 0;
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        fprintf(stderr,"usage: %s path\n",argv[0]);
        exit(1);
    }

    // Delete the directory and its contents by traversing the tree in reverse order, without crossing mount boundaries and symbolic links

    if (nftw(argv[1], rmFiles,10, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) < 0)
    {
        perror("ERROR: ntfw");
        exit(1);
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)


小智 7

C++17有<experimental\filesystem>基于boost版本。

使用std::experimental::filesystem::remove_all递归删除。

如果您需要更多控制,请尝试std::experimental::filesystem::recursive_directory_iterator

您还可以使用迭代器的非递归版本编写自己的递归。

namespace fs = std::experimental::filesystem;
void IterateRecursively(fs::path path)
{
  if (fs::is_directory(path))
  {
    for (auto & child : fs::directory_iterator(path))
      IterateRecursively(child.path());
  }

  std::cout << path << std::endl;
}
Run Code Online (Sandbox Code Playgroud)