在 C 或 C++ 中以编程方式删除非空目录
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2256945/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Removing a non empty directory programmatically in C or C++
提问by avd
How to delete a non empty directory in C or C++? Is there any function? rmdir only deletes empty directory. Please provide a way without using any external library.
如何删除 C 或 C++ 中的非空目录?有什么功能吗?rmdir 只删除空目录。请提供一种不使用任何外部库的方法。
Also tell me how to delete a file in C or C++?
还告诉我如何删除 C 或 C++ 中的文件?
采纳答案by asveikau
You want to write a function (a recursive function is easiest, but can easily run out of stack space on deep directories) that will enumerate the children of a directory. If you find a child that is a directory, you recurse on that. Otherwise, you delete the files inside. When you are done, the directory is empty and you can remove it via the syscall.
您想编写一个函数(递归函数最简单,但很容易用完深层目录的堆栈空间)来枚举目录的子目录。如果你发现一个子目录是一个目录,你就会递归它。否则,你删除里面的文件。完成后,该目录为空,您可以通过系统调用将其删除。
To enumerate directories on Unix, you can use opendir(), readdir(), and closedir(). To remove you use rmdir()on an empty directory (i.e. at the end of your function, after deleting the children) and unlink()on a file. Note that on many systems the d_typemember in struct direntis not supported; on these platforms, you will have to use stat()and S_ISDIR(stat.st_mode)to determine if a given path is a directory.
枚举在Unix上的目录,你可以使用opendir(),readdir()和closedir()。要删除您rmdir()在空目录上使用(即在您的函数末尾,删除子项后)和unlink()文件。请注意,在许多系统上d_type,struct dirent不支持成员 in ;在这些平台上,您必须使用stat()并S_ISDIR(stat.st_mode)确定给定的路径是否为目录。
On Windows, you will use FindFirstFile()/FindNextFile()to enumerate, RemoveDirectory()on empty directories, and DeleteFile()to remove files.
在 Windows 上,您将使用FindFirstFile()/FindNextFile()来枚举、RemoveDirectory()空目录和DeleteFile()删除文件。
Here's an example that might work on Unix (completely untested):
这是一个可能适用于 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;
}
回答by Andrew Gunnerson
Many unix-like systems (Linux, the BSDs, and OS X, at the very least) have the ftsfunctions for directory traversal.
许多unix类似的系统(至少Linux,BSDs 和OS X)具有fts目录遍历功能。
To recursively delete a directory, perform a depth-first traversal (without following symlinks) and remove every visited file:
要递归删除目录,请执行深度优先遍历(不使用符号链接)并删除每个访问过的文件:
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(curr->fts_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(curr->fts_errno));
ret = -1;
}
break;
}
}
finish:
if (ftsp) {
fts_close(ftsp);
}
return ret;
}
回答by marcmagransdeabril
If you are using a POSIX compliant OS, you could use nftw()for file tree traversal and remove (removes files or directories). If you are in C++ and your project uses boost, it is not a bad idea to use the Boost.Filesystem as suggested by Manuel.
如果您使用的是符合 POSIX 的操作系统,则可以nftw()用于文件树遍历和删除(删除文件或目录)。如果您使用的是 C++ 并且您的项目使用了 boost,那么按照 Manuel 的建议使用 Boost.Filesystem 是一个不错的主意。
In the code example below I decided not to traverse symbolic links and mount points (just to avoid a grand removal:) ):
在下面的代码示例中,我决定不遍历符号链接和挂载点(只是为了避免大规模删除:)):
#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;
}
回答by Manuel
The easiest way to do this is with remove_allfunction of the Boost.Filesystem library. Besides, the resulting code will be portable.
最简单的方法是使用Boost.Filesystem 库的remove_all函数。此外,生成的代码将是可移植的。
If you want to write something specific for Unix (rmdir) or for Windows (RemoveDirectory) then you'll have to write a function that deletes are subfiles and subfolders recursively.
如果您想为 Unix (rmdir) 或 Windows (RemoveDirectory) 编写一些特定的内容,那么您必须编写一个函数来递归地删除子文件和子文件夹。
EDIT
编辑
Looks like this question was already asked, in fact someone already recommended Boost's remove_all. So please don't upvote my answer.
回答by Xorlev
unlinkwill delete a file.
unlink将删除一个文件。
removewill also delete a file but is more portable.
remove也会删除文件,但更便于携带。
You might try system("rm -r ./path")if you're working on Linux, else there's also a Windows API recursive delete function.
system("rm -r ./path")如果你在 Linux 上工作,你可以试试,否则还有一个 Windows API 递归删除功能。
回答by diciu
You can use opendirand readdirto read directory entries and unlinkto delete them.
您可以使用opendir和readdir读取目录条目并取消链接以删除它们。
回答by greedy52
C++17 has <experimental\filesystem>which is based on the boost version.
C++17 有<experimental\filesystem>基于 boost 版本的。
Use std::experimental::filesystem::remove_allto remove recursively.
使用std::experimental::filesystem::remove_all递归删除。
If you need more control, try std::experimental::filesystem::recursive_directory_iterator.
如果您需要更多控制,请尝试std::experimental::filesystem::recursive_directory_iterator。
You can also write your own recursion with the non-resursive version of the 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;
}
回答by Samson Praneeth
How to delete a non empty folder using unlinkat() in c?
如何在c中使用unlinkat()删除非空文件夹?
Here is my work on it:
这是我的工作:
/*
* Program to erase the files/subfolders in a directory given as an input
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void remove_dir_content(const char *path)
{
struct dirent *de;
char fname[300];
DIR *dr = opendir(path);
if(dr == NULL)
{
printf("No file or directory found\n");
return;
}
while((de = readdir(dr)) != NULL)
{
int ret = -1;
struct stat statbuf;
sprintf(fname,"%s/%s",path,de->d_name);
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
continue;
if(!stat(fname, &statbuf))
{
if(S_ISDIR(statbuf.st_mode))
{
printf("Is dir: %s\n",fname);
printf("Err: %d\n",ret = unlinkat(dirfd(dr),fname,AT_REMOVEDIR));
if(ret != 0)
{
remove_dir_content(fname);
printf("Err: %d\n",ret = unlinkat(dirfd(dr),fname,AT_REMOVEDIR));
}
}
else
{
printf("Is file: %s\n",fname);
printf("Err: %d\n",unlink(fname));
}
}
}
closedir(dr);
}
void main()
{
char str[10],str1[20] = "../",fname[300]; // Use str,str1 as your directory path where it's files & subfolders will be deleted.
printf("Enter the dirctory name: ");
scanf("%s",str);
strcat(str1,str);
printf("str1: %s\n",str1);
remove_dir_content(str1); //str1 indicates the directory path
}
回答by Bill Moore
//======================================================
// Recursely Delete files using:
// Gnome-Glib & C++11
//======================================================
#include <iostream>
#include <string>
#include <glib.h>
#include <glib/gstdio.h>
using namespace std;
int DirDelete(const string& path)
{
const gchar* p;
GError* gerr;
GDir* d;
int r;
string ps;
string path_i;
cout << "open:" << path << "\n";
d = g_dir_open(path.c_str(), 0, &gerr);
r = -1;
if (d) {
r = 0;
while (!r && (p=g_dir_read_name(d))) {
ps = string{p};
if (ps == "." || ps == "..") {
continue;
}
path_i = path + string{"/"} + p;
if (g_file_test(path_i.c_str(), G_FILE_TEST_IS_DIR) != 0) {
cout << "recurse:" << path_i << "\n";
r = DirDelete(path_i);
}
else {
cout << "unlink:" << path_i << "\n";
r = g_unlink(path_i.c_str());
}
}
g_dir_close(d);
}
if (r == 0) {
r = g_rmdir(path.c_str());
cout << "rmdir:" << path << "\n";
}
return r;
}

