文章目录
- 一、简介
- 二、代码演示
一、简介
Linux 下可以使用 rmdir 系统调用来删除一个目录,但是只能删除一个非空目录。
NAMErmdir - delete a directorySYNOPSIS#include <unistd.h>int rmdir(const char *pathname);DESCRIPTIONrmdir() deletes a directory, which must be empty.
在 shell命令行我们用 rm -rf 来删除一个目录,那我们仿照 rm -rf 的原理来实现一个使用C语言删除一个非空的目录。
当执行 rm -rf 命令时,它会按照以下步骤进行操作:
首先,命令会尝试打开指定的目录 <directory>。
如果成功打开目录,命令会遍历目录中的所有子目录和文件。
对于每个子目录和文件,命令会递归调用自身,以便删除子目录和文件。
如果遇到子目录,将按照相同的步骤递归删除子目录及其内容。
如果遇到文件,命令将直接删除文件。
删除完成后,命令关闭目录。
(1)使用 tree 命令查看目录结构:
# tree dir_test/
dir_test/
├── 3.txt
├── 4.txt
├── 5.txt
└── dir1├── 1.txt└── 2.txt1 directory, 5 files
(2)使用 strace 来 追踪 rm -rf 命令:
[root@localhost c_test]# strace -e trace=file rm -rf dir_test/
execve("/usr/bin/rm", ["rm", "-rf", "dir_test/"], 0x7ffe2a252c50 /* 27 vars */) = 0
......
newfstatat(AT_FDCWD, "dir_test/", {st_mode=S_IFDIR|0755, st_size=57, ...}, AT_SYMLINK_NOFOLLOW) = 0
openat(AT_FDCWD, "dir_test/", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_DIRECTORY) = 3
openat(AT_FDCWD, "dir_test/", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_DIRECTORY) = 3
newfstatat(4, "dir1", {st_mode=S_IFDIR|0755, st_size=32, ...}, AT_SYMLINK_NOFOLLOW) = 0
openat(4, "dir1", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_DIRECTORY) = 3
openat(4, "dir1", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_DIRECTORY) = 3
unlinkat(5, "1.txt", 0) = 0
unlinkat(5, "2.txt", 0) = 0
unlinkat(4, "dir1", AT_REMOVEDIR) = 0
unlinkat(4, "3.txt", 0) = 0
unlinkat(4, "4.txt", 0) = 0
unlinkat(4, "5.txt", 0) = 0
unlinkat(AT_FDCWD, "dir_test/", AT_REMOVEDIR) = 0
主要是:
unlinkat(5, "1.txt", 0) = 0
unlinkat(5, "2.txt", 0) = 0
unlinkat(4, "dir1", AT_REMOVEDIR) = 0
unlinkat(4, "3.txt", 0) = 0
unlinkat(4, "4.txt", 0) = 0
unlinkat(4, "5.txt", 0) = 0
unlinkat(AT_FDCWD, "dir_test/", AT_REMOVEDIR) = 0
可以看到删除一个目录,首先将该目录下的文件删除掉,然后再删除掉该空目录。
二、代码演示
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <limits.h>void removeDirectory(const char* dirPath) {struct stat st;if (lstat(dirPath, &st) == -1) {perror("lstat");return;}if (S_ISDIR(st.st_mode)) {DIR* dir = opendir(dirPath);if (dir == NULL) {perror("opendir");return;}char path[PATH_MAX];struct dirent* entry;while ((entry = readdir(dir)) != NULL) {if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {continue;}snprintf(path, sizeof(path), "%s/%s", dirPath, entry->d_name);removeDirectory(path);}closedir(dir);if (rmdir(dirPath) == -1) {perror("rmdir");return;}printf("Directory %s deleted successfully.\n", dirPath);} else if (S_ISREG(st.st_mode)) {if (remove(dirPath) == -1) {perror("remove");return;}printf("File %s deleted successfully.\n", dirPath);} else {printf("%s is of unknown file type.\n", dirPath);}
}int main(int argc, char* argv[]) {if (argc != 2) {printf("Usage: %s <file_path>\n", argv[0]);return 1;}const char* filePath = argv[1];removeDirectory(filePath);return 0;
}
# ./a.out dir_test/
File dir_test//dir1/1.txt deleted successfully.
File dir_test//dir1/2.txt deleted successfully.
Directory dir_test//dir1 deleted successfully.
File dir_test//3.txt deleted successfully.
File dir_test//4.txt deleted successfully.
File dir_test//5.txt deleted successfully.
Directory dir_test/ deleted successfully.
unlinkat(5, "1.txt", 0) = 0
unlinkat(5, "2.txt", 0) = 0
unlinkat(4, "dir1", AT_REMOVEDIR) = 0
unlinkat(4, "3.txt", 0) = 0
unlinkat(4, "4.txt", 0) = 0
unlinkat(4, "5.txt", 0) = 0
unlinkat(AT_FDCWD, "dir_test/", AT_REMOVEDIR) = 0
可以看到和 rm -rf 命令删除非空目录过程相同。