当前位置: 首页 > news >正文

Linux下目录遍历的实现

1.实验目的

  1. 掌握Linux目录操作方法
    1. 打开目录、关闭目录
    2. 读取目录文件
  2. 掌握Linux文件属性获取方法
    1. 三个获取Linux文件属性的函数
  3. 掌握文件属性解析相关的重要数据结构、函数和宏定义

2.实验内容

利用POSIX API和文件属性解析的相关宏在Linux系统上编写应用程序,实现ls命令的部分功能(执行“ls -l”的功能),参数通过命令行参数传入,包括:

  1. 获取当前工作目录路径并对该目录实现遍历
  2. 以列表形式出当前工作目录下的所有文件(包括子目录),并显示每个文件的属性信息(文件类型、文件权限、文件硬链接数、文件所有者用户名、文件所有者所在组用户名、文件大小、文件最后修改时间)

在实现基本功能实现的基础上,针对各种特殊情况和边界条件等进行流程的完善与优化,包括

  1. 根据命令行参数决定是否显示当前目录本身“.”和上级目录“..”
  2. 根据命令行参数决定是否显示隐藏文件(文件名以“.”作为开始的文件)
  3. 根据命令行参数决定是显示符号链接文件本身的属性还是符号链接指向文件的文件属性

3.代码分析

例子说明:

        命令行输入:./myprogram -a -l file.txt

        内存中argv数组:
                argv[0] = "./myprogram"  ← 程序名
                argv[1] = "-a"           ← 第1个参数
                argv[2] = "-l"           ← 第2个参数
                argv[3] = "file.txt"     ← 第3个参数
                argv[4] = NULL           ← 结束标记

        此时argc = 4

3.1 头文件分析

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
  • <dirent.h>:目录操作头文件
  • <sys/stat.h>:文件状态头文件
  • <pwd.h>:用户信息头文件
  • <grp.h>:组信息头文件

3.2 main函数分析

3.2.1初始化参数标志

  int show_hidden = 0;          // 不显示隐藏文件int show_dot = 0;             // 不显示"."和".."int follow_links = 0;         // 不跟随符号链接const char *target_dir = "."; // 默认当前目录

3.2.2解析命令行参数

for (int i = 1; i < argc; i++){// 处理选项参数if (argv[i][0] == '-'){// 处理组合选项,如 -alfor (int j = 1; argv[i][j] != '\0'; j++){switch (argv[i][j]){case 'a': // 显示所有文件,包括隐藏文件和"."、".."show_hidden = 1;show_dot = 1;break;case 'A': // 显示隐藏文件但不显示"."和".."show_hidden = 1;show_dot = 0;break;case 'L': // 跟随符号链接follow_links = 1;break;case 'h': // 帮助信息print_usage(argv[0]);exit(EXIT_SUCCESS);default:fprintf(stderr, "错误: 未知选项 '-%c'\n", argv[i][j]);print_usage(argv[0]);exit(EXIT_FAILURE);}}}// 处理目录参数else{// 检查是否已经指定了目录if (strcmp(target_dir, ".") != 0){fprintf(stderr, "错误: 只能指定一个目录\n");print_usage(argv[0]);exit(EXIT_FAILURE);}target_dir = argv[i];}}

        核心是一个嵌套循环,argc是参数个数,argv是一个指向字符串数组的指针。argv[i][j]指的是第i个参数,也就是第i个字符串下的第j个字符。这个通过遍历每个字符串的每一个字符,就能查到到对应命令的方法。

 // 验证目录是否存在并可访问DIR *dir = opendir(target_dir);if (dir == NULL){perror("错误: 无法访问目录");fprintf(stderr, "目录: %s\n", target_dir);exit(EXIT_FAILURE);}closedir(dir);
// 调用目录列表函数list_directory(target_dir, show_hidden, show_dot, follow_links);return EXIT_SUCCESS;

3.3目录列表函数

void list_directory(const char *dirname, int show_hidden, int show_dot, int follow_links)
{DIR *dir;struct dirent *entry;struct stat file_stat;if ((dir = opendir(dirname)) == NULL){perror("opendir");return;}while ((entry = readdir(dir)) != NULL){// 跳过隐藏文件和特殊目录(根据参数决定)if (entry->d_name[0] == '.'){if (!show_hidden)continue;if (!show_dot && (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)){continue;}}// 构建完整路径char path[1024];snprintf(path, sizeof(path), "%s/%s", dirname, entry->d_name);// 获取文件属性if (follow_links){if (stat(path, &file_stat) == -1){perror("stat");continue;}}else{if (lstat(path, &file_stat) == -1){perror("lstat");continue;}}// 显示文件信息display_file_info(entry->d_name, &file_stat, follow_links);}closedir(dir);
}
  • dirname:要遍历的目录路径
  • show_hidden:是否显示隐藏文件
  • show_dot:是否显示特殊目录
  • follow_links:是否跟随符号链接

        通过一个while循环,来循环读取目录中的每个条目。后面会通过是否跟随符号链接,来返回目标文件的属性。

3.4显示文件信息

void display_file_info(const char *filename, const struct stat *file_stat, int show_link_target)
{// 打印文件类型和权限print_file_type(file_stat->st_mode);print_permissions(file_stat->st_mode);// 打印硬链接数printf("%2ld ", file_stat->st_nlink);// 打印所有者和组struct passwd *pwd = getpwuid(file_stat->st_uid);struct group *grp = getgrgid(file_stat->st_gid);printf("%-8s %-8s ", pwd->pw_name, grp->gr_name);// 打印文件大小printf("%8ld ", file_stat->st_size);// 打印修改时间char time_buf[64];strftime(time_buf, sizeof(time_buf), "%b %d %H:%M", localtime(&file_stat->st_mtime));printf("%s ", time_buf);// 打印文件名printf("%s", filename);// 如果是符号链接且不跟随,打印链接目标if (S_ISLNK(file_stat->st_mode) && !show_link_target){char link_target[1024];ssize_t len = readlink(filename, link_target, sizeof(link_target) - 1);if (len != -1){link_target[len] = '\0';printf(" -> %s", link_target);}}printf("\n");
}void print_permissions(mode_t mode)
{printf("%c", (mode & S_IRUSR) ? 'r' : '-');printf("%c", (mode & S_IWUSR) ? 'w' : '-');printf("%c", (mode & S_IXUSR) ? 'x' : '-');printf("%c", (mode & S_IRGRP) ? 'r' : '-');printf("%c", (mode & S_IWGRP) ? 'w' : '-');printf("%c", (mode & S_IXGRP) ? 'x' : '-');printf("%c", (mode & S_IROTH) ? 'r' : '-');printf("%c", (mode & S_IWOTH) ? 'w' : '-');printf("%c", (mode & S_IXOTH) ? 'x' : '-');printf(" ");
}void print_file_type(mode_t mode)
{if (S_ISREG(mode))printf("-");else if (S_ISDIR(mode))printf("d");else if (S_ISLNK(mode))printf("l");else if (S_ISCHR(mode))printf("c");else if (S_ISBLK(mode))printf("b");else if (S_ISFIFO(mode))printf("p");else if (S_ISSOCK(mode))printf("s");elseprintf("?");
}

4.实验结果

相关文章:

  • 机器学习算法-决策树
  • Linux操作系统概述
  • 【文献阅读】EndoChat: Grounded Multimodal Large Language Model for Endoscopic Surgery
  • AI前端开发岗位面试准备指南
  • MATLAB绘制滤波器系数特性图
  • 【机器学习基础】机器学习入门核心算法:K-近邻算法(K-Nearest Neighbors, KNN)
  • 大模型——MCP 深度解析
  • day 38
  • python-自定义导包问题ModuleNotFoundError: No module named
  • uni-app 中开发问题汇总
  • 走进黑盒:SQL 是如何在数据库中执行的?
  • 大模型应用:开发移动端页面个人中心页面提示词
  • CVPR2022——立体匹配算法Fast-ACVNet复现
  • 不同数据场景下的聚类算法
  • MybatisPlus - Interceptor(拦截器)的功能点
  • 完全卸载VS Code--Windows版
  • 图文详解 | PhotoScape X Pro 4.2.5 安装步骤与功能初探
  • 003大模型-大模型API调用,function calling的作用以及本地调用
  • 枪弹库专用门
  • Linux挂载新硬盘保姆级教程
  • 杭州建设网站/新的营销模式有哪些
  • 渠道网关/重庆seo优
  • 网站如何做点击链接地址/成功的软文营销案例
  • 网站框架一般用什么做/微信管理系统平台
  • 做微商那个网站好/百度推广人联系方式
  • 做一家算命的网站/宁波网站推广哪家公司好