在Linux中实现打印目录程序遇到问题及解决

本文详细解析了一段Linux程序设计中用于打印目录结构的代码,包括关键函数的作用,如opendir()、readdir()和lstat()。程序采用递归方式,通过比较目录名判断是否为根目录或父目录,利用printf的格式化输出控制缩进,呈现清晰的目录层级。此外,还介绍了如何处理无法打开目录的情况。
摘要由CSDN通过智能技术生成

在Linux中实现打印目录程序

今日阅读Linux程序设计第四版时,书中给出了一段实例代码,功能为实现/home目录下各级目录结构,当然不一定非得是/home下目录才可以,任何一级目录都可以。
书中代码展示
自己尝试在Ubuntu系统运行编译,实现效果如下:
效果展示
自己对该程序各行代码进行一个解读分析,同时查阅各项资料:

首先定义打印目录的函数

void printdir(char *dir ,int depth)

char *dir代表DIR目录名,int depth设置当前目录打印后所占空格位置

接下来定义函数内需要的三项参数

  DIR *dp;              /*申请一个目录指针*/
  struct dirent *entry;/*申请一个结构体指针,该结构体包含目录和文件信息*/
  struct stat statbuf;  /*申请一个结构体,该结构体用于之后各级目录内文件访问权限的判定*/

通过查阅资料:
该部分中DIR,dirent和stat经常相互配合和使用。
DIR结构体是一个目录流指针,用于完成各项目录操作
dirent则类比于一个一个接受DIR指针传来目录,并将这个目录进一步细分化,引导到stat当中的中间站
stat则储存着各项目录内具体的文件信息
三者是一种递进的关系

接下来对输入参数有效性进行判断

if((dp = opendir(dir)) == NULL){ /*函数 DIR *opendir(const char *pathname),即打开文件目录,返回的就是指向DIR结构体的指针*/
    fprintf(stderr,"cannot open directory: %s\n",dir);
    return;
  }                     /*如果无法打开该目录,则直接打印该层目录信息*/
  
  chdir(dir);           /*chdir(const char * path)用于把当前工作目录更改为参数路径指示目录*/

该部分主要完成从目录到目录指针,以及判定是否为目录的操作
DIR *opendir(const char *pathname),即打开文件目录,返回的就是指向DIR结构体的指针

最后进行打印目录操作:

while((entry = readdir(dp)) != NULL){
     
    lstat(entry->d_name,&statbuf);      /* 该步骤将相关文件路径名字对应的文件结构体放入stat结构中 */
	
    if(S_ISDIR(statbuf.st_mode)){       /* S_ISDIR宏用于判断传入参数是否是一个目录 */

      if(strcmp(".",entry->d_name) == 0 || strcmp("..",entry->d_name) == 0)/*如果到达根目录或者路径名为.,则跳过去该部分*/
	continue;
      printf("%*s%s/\n",depth,"",entry->d_name);       
	  /*   假如depth等于5,可类比为:printf("%5s%s/\n","",entry->d_name)  此处留出depth的空格来,随后写入目录对应的文件名,然后另起一行  */
      printdir(entry->d_name,depth+4);
    }
    else printf("%*s%s\n",depth,"",entry->d_name);
  }/*该部分用于逐级循环,自上而下读入目录,返回各级目录指针*/
  
  chdir("..");
  closedir(dp);

具体部分功能已经标注,另外说明
printf("%*s%s/\n",depth,"",entry->d_name)
该函数中%*s的※号代表接受后面的一个int参数变量,假设当前depth等于5,则类比为printf("%5s%s/\n","",entry->d_name) ,意思是先空出5个空格来,再进行目录打印。

为什么需要这样子?
因为目录在没完成单个文件名打印后需要另起一行,但是级别更加靠近根节点目录理应更加靠前,反之需要靠后。
在这里插入图片描述
该部分采用了递归方法:

printf("%*s%s/\n",depth,"",entry->d_name);       
	  /*   假如depth等于5,可类比为:printf("%5s%s/\n","",entry->d_name)  此处留出depth的空格来,随后写入目录对应的文件名,然后另起一行  */
      printdir(entry->d_name,depth+4);
    }
    else printf("%*s%s\n",depth,"",entry->d_name);
  }/*该部分用于逐级循环,自上而下读入目录,返回各级目录指针*/

所以在每一层可以保留自己所在层的需要空出来的depth具体值。

全部代码如下:

#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>

void printdir(char *dir ,int depth)
{
  DIR *dp;              /*申请一个目录指针*/
  struct dirent *entry;/*申请一个结构体指针,该结构体包含目录和文件信息*/
  struct stat statbuf;  /*申请一个结构体,该结构体用于之后各级目录内文件访问权限的判定*/
  
  if((dp = opendir(dir)) == NULL){ /*函数 DIR *opendir(const char *pathname),即打开文件目录,返回的就是指向DIR结构体的指针*/
    fprintf(stderr,"cannot open directory: %s\n",dir);
    return;
  }                     /*如果无法打开该目录,则直接打印该层目录信息*/
  
  chdir(dir);           /*chdir(const char * path)用于把当前工作目录更改为参数路径指示目录*/
  
  while((entry = readdir(dp)) != NULL){
     
    lstat(entry->d_name,&statbuf);      /* 该步骤将相关文件路径名字对应的文件结构体放入stat结构中 */
	
    if(S_ISDIR(statbuf.st_mode)){       /* S_ISDIR宏用于判断传入参数是否是一个目录 */

      if(strcmp(".",entry->d_name) == 0 || strcmp("..",entry->d_name) == 0)/*如果到达根目录或者路径名为.,则跳过去该部分*/
	continue;
      printf("%*s%s/\n",depth,"",entry->d_name);       
	  /*   假如depth等于5,可类比为:printf("%5s%s/\n","",entry->d_name)  此处留出depth的空格来,随后写入目录对应的文件名,然后另起一行  */
      printdir(entry->d_name,depth+4);
    }
    else printf("%*s%s\n",depth,"",entry->d_name);
  }/*该部分用于逐级循环,自上而下读入目录,返回各级目录指针*/
  
  chdir("..");
  closedir(dp);
}

int main()
{
  printf("Directory scan of /home:\n");
  printdir("/home",0);
  printf("done.\n");

  exit(0);
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值