TLPI读书笔记第18章-目录与链接3
1.列出目录中的所有文件
/* Listing 18-2 */ /* list_files.c*/ #if defined(__APPLE__) /* Darwin requires this header before including <dirent.h> */ #include <sys/types.h> #endif #include <dirent.h> #include "tlpi_hdr.h" static void /* 列出目录'dirpath'的所有文件 */ listFiles(const char *dirpath) { DIR *dirp; struct dirent *dp; Boolean isCurrent; /* 判断dirpath是否是当前目录. */ isCurrent = strcmp(dirpath, ".") == 0; /**打开指定目录,返回一个DIR指针*/ dirp = opendir(dirpath); if (dirp == NULL) { errMsg("opendir failed on '%s'", dirpath); return; } /* 读取每个DIR条目,打印目录+文件名 */ for (;;) { errno = 0; /* 打印readdir过程中错误 */ dp = readdir(dirp); if (dp == NULL) break; /**如果d_name是.或..,继续循环*/ if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) continue; /**如果是当前目录,则不打印dir部分*/ if (!isCurrent) printf("%s/", dirpath); printf("%s\n", dp->d_name); } if (errno != 0) errExit("readdir"); if (closedir(dirp) == -1) errMsg("closedir"); } int main(int argc, char *argv[]) { if (argc > 1 && strcmp(argv[1], "--help") == 0) usageErr("%s [dir-path...]\n", argv[0]); if (argc == 1) /* 没有传参数,则默认是当前目录. */ listFiles("."); else for (argv++; *argv; argv++) listFiles(*argv); exit(EXIT_SUCCESS); }
2.递归遍历目录
/* Listing 18-3 */ /* nftw_dir_tree.c */ #if defined(__sun) #define _XOPEN_SOURCE 500 /* Solaris 8 needs it this way */ #else #if ! defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 600 #define _XOPEN_SOURCE 600 /* Get nftw() and S_IFSOCK declarations */ #endif #endif #include <ftw.h> #include "tlpi_hdr.h" static void usageError(const char *progName, const char *msg) { if (msg != NULL) fprintf(stderr, "%s\n", msg); fprintf(stderr, "Usage: %s [-d] [-m] [-p] [directory-path]\n", progName); fprintf(stderr, "\t-d Use FTW_DEPTH flag\n"); fprintf(stderr, "\t-m Use FTW_MOUNT flag\n"); fprintf(stderr, "\t-p Use FTW_PHYS flag\n"); exit(EXIT_FAILURE); } static int /* 自定义函数,以备nftw()调用 */ dirTree(const char *pathname, const struct stat *sbuf, int type,struct FTW *ftwb) { if (type == FTW_NS) { /* 调用stat失败 */ printf("?"); } else { switch (sbuf->st_mode & S_IFMT) { /* 打印文件类型 */ case S_IFREG: printf("-"); break; case S_IFDIR: printf("d"); break; case S_IFCHR: printf("c"); break; case S_IFBLK: printf("b"); break; case S_IFLNK: printf("l"); break; case S_IFIFO: printf("p"); break; case S_IFSOCK: printf("s"); break; default: printf("?"); break; /* Should never happen (on Linux) */ } } printf(" %s ", (type == FTW_D) ? "D " : (type == FTW_DNR) ? "DNR" : (type == FTW_DP) ? "DP " : (type == FTW_F) ? "F " : (type == FTW_SL) ? "SL " : (type == FTW_SLN) ? "SLN" : (type == FTW_NS) ? "NS " : " "); if (type != FTW_NS) printf("%7ld ", (long) sbuf->st_ino); else printf(" "); printf(" %*s", 4 * ftwb->level, ""); /* 用缩进代表级别 */ printf("%s\n", &pathname[ftwb->base]); /* 打印basename */ return 0; /* Tell nftw() to continue */ } int main(int argc, char *argv[]) { int flags, opt; flags = 0; while ((opt = getopt(argc, argv, "dmp")) != -1) { switch (opt) { case 'd': flags |= FTW_DEPTH; break;/*后序遍历*/ case 'm': flags |= FTW_MOUNT; break;/*不越界进入另一个文件系统*/ case 'p': flags |= FTW_PHYS; break;/*不对符号链接解引用*/ default: usageError(argv[0], NULL); } } if (argc > optind + 1) usageError(argv[0], NULL); if (nftw((argc > optind) ? argv[optind] : ".", dirTree, 10, flags) == -1) { perror("nftw"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
3.打印路径中的目录和文件名
/* Listing 18-5 */ /* t_dirbasename.c */ #include <libgen.h> #include "tlpi_hdr.h" /**打印路径的目录部分和文件名部分 * dirname()和 basename()均可修改pathname所指向的字符串。 * 因此,如果希望保留原有的路径名字符串,那么就必须向 dirname()和 basename()传递该字符串的副本 * 使用strdup()该函数调用了 malloc()来制作传递给dirname()和basename()的字符串副本, * 然后再使用 free()将其释放 * */ int main(int argc, char *argv[]) { char *t1, *t2; int j; for (j = 1; j < argc; j++) { t1 = strdup(argv[j]); if (t1 == NULL) errExit("strdup"); t2 = strdup(argv[j]); if (t2 == NULL) errExit("strdup"); printf("%s ==> %s + %s\n", argv[j], dirname(t1), basename(t2)); free(t1); free(t2); } exit(EXIT_SUCCESS); }
4.unlink的应用
/* Listing 18-1 */ /** t_unlink.c 一个文件被unlink,当他还有被打开的文件描述符时他实际是没有被删的, 此时还能进行写入,close(fd)后文件才真正被删 Usage: t_unlink file */ #include <sys/stat.h> #include <fcntl.h> #include "tlpi_hdr.h" #define CMD_SIZE 200 #define BUF_SIZE 1024 int main(int argc, char *argv[]) { int fd, j, numBlocks; char shellCmd[CMD_SIZE]; /* 调用的shell命令 */ char buf[BUF_SIZE]; /* 随机写入一定字节 */ if (argc < 2 || strcmp(argv[1], "--help") == 0) usageErr("%s temp-file [num-1kB-blocks] \n", argv[0]); numBlocks = (argc > 2) ? getInt(argv[2], GN_GT_0, "num-1kB-blocks") : 100000; /* 创建一个新文件 */ fd = open(argv[1], O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); if (fd == -1) errExit("open"); if (unlink(argv[1]) == -1) /* 删除文件 */ errExit("unlink"); for (j = 0; j < numBlocks; j++) /* 写入文件 */ if (write(fd, buf, BUF_SIZE) != BUF_SIZE) fatal("partial/failed write"); /**将命令df写入shellCmd中,并执行shell命令*/ snprintf(shellCmd, CMD_SIZE, "df -k `dirname %s`", argv[1]); system(shellCmd); /* 查看文件占用空间 */ if (close(fd) == -1) /* 关闭文件描述符,此时文件才被删除 */ errExit("close"); printf("********** Closed file descriptor\n"); system(shellCmd); /* 重新查看占用空间 */ exit(EXIT_SUCCESS); }
5.读取并解析一个符号链接
/* Listing 18-4 */ /* view_symlink.c 读取并解析一个符号链接 */ #include <sys/stat.h> #include <limits.h> /* For definition of PATH_MAX */ #include "tlpi_hdr.h" #define BUF_SIZE PATH_MAX int main(int argc, char *argv[]) { struct stat statbuf; char buf[BUF_SIZE]; ssize_t numBytes; if (argc != 2 || strcmp(argv[1], "--help") == 0) usageErr("%s pathname\n", argv[0]); /* 检查提供的路径名是否为一个符号链接 */ if (lstat(argv[1], &statbuf) == -1) errExit("lstat"); if (!S_ISLNK(statbuf.st_mode)) fatal("%s is not a symbolic link", argv[1]); numBytes = readlink(argv[1], buf, BUF_SIZE - 1); if (numBytes == -1) errExit("readlink"); buf[numBytes] = '\0'; /* 添加终止空字节,并打印 */ printf("readlink: %s --> %s\n", argv[1], buf); if (realpath(argv[1], buf) == NULL) errExit("realpath"); printf("realpath: %s --> %s\n", argv[1], buf); exit(EXIT_SUCCESS); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端