如何在C或C ++中删除非空目录?有什么功能吗? rmdir只删除空目录。请提供一种不使用任何外部库的方法。
还告诉我如何用C或C ++删除文件?
答案 0 :(得分:28)
您希望编写一个函数(递归函数最简单,但很容易耗尽深层目录中的堆栈空间),它将枚举目录的子级。如果您发现某个孩子是一个目录,那么您可以对此进行说明。否则,您删除里面的文件。完成后,目录为空,您可以通过系统调用将其删除。
要在Unix上枚举目录,您可以使用opendir
,readdir
和closedir
。要删除您在空目录(即功能结束时,删除子项后)和文件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;
}
答案 1 :(得分:14)
最简单的方法是使用Boost.Filesystem库的remove_all函数。此外,生成的代码将是可移植的。
如果你想编写针对Unix(rmdir)或Windows(RemoveDirectory)的特定内容,那么你必须编写一个以递归方式删除子文件和子文件夹的函数。
修改强>
看起来这个问题是already asked,事实上有人已经推荐了Boost的remove_all。所以请不要回答我的回答。
答案 2 :(得分:14)
许多类似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;
}
答案 3 :(得分:11)
如果您使用的是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;
}
答案 4 :(得分:1)
您可以使用 opendir 和 readdir 来读取目录条目,并使用取消链接来删除它们。
答案 5 :(得分:1)
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;
}
答案 6 :(得分:0)
unlink
将删除文件。
remove
也会删除文件但更便携。
如果您正在使用Linux,则可以尝试system("rm -r ./path")
,否则还会有Windows API递归删除功能。
答案 7 :(得分:0)
//======================================================
// 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;
}
答案 8 :(得分:0)
如何在c中使用unlinkat()删除非空文件夹?
这是我的工作:
/*
* 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
}