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

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.实验结果

http://www.xdnf.cn/news/9365.html

相关文章:

  • 各个链接集合
  • 在h5端实现录音发送功能(兼容内嵌微信小程序) recorder-core
  • java-jdk8新特性Stream流
  • 交叉编译工具链冲突
  • nRF Connect SDK开发之(2)编译一个例程
  • 分布式系统
  • ORB-SLAM2学习笔记:ORBextractor的构造函数详解
  • HOW - 从0到1搭建自己的博客站点(四)
  • 10.2sql
  • python-正则表达式
  • 与 PyCharm 官方沟通解决开发环境问题记录(进展:官方已推出2个新的修复版本)
  • C语言-文件
  • IEEE Journal on Selected Areas in Communications 2025年论文整理2(中英文摘要)
  • IPv4地址的主要配置项介绍
  • 14. LayUI与Bootstrap框架使用
  • JS手写代码篇---手写promise.all
  • Python条件语句完全指南:从if-else到模式匹配
  • 鸿蒙OSUniApp 实现带搜索功能的下拉菜单#三方框架 #Uniapp
  • 实验设计与分析(第6版,Montgomery)第3章单因子实验:方差分析3.11思考题3.1 R语言解题
  • PIO 也有并发喔,巧用SIDE-SET
  • 解决Qt 打包的软件缺少dll问题
  • 《计算机组成原理》第 4 章 - 存储器​
  • 零基础设计模式——结构型模式 - 装饰器模式
  • 国芯思辰| 同步降压转换器CN2020应用于智能电视,替换LMR33620
  • 在ubuntu手动分区时,730GB的总空间,建议划分多少给根目录
  • AI应用 Markdown 渲染对比与原生实现方案
  • 书籍品读:《逆水行舟话幸福》(陈州)
  • 【Python】2. 基础语法(2)
  • 【运维_日常报错解决方案_docker系列】一、docker系统不起来
  • 从自动化到智能化:制造业数字化转型的五个关键跃迁