实现“ls -l”的基本功能

1.题目解析

ls -l这个查询所输出的分别是文件的权限信息、硬链接数、用户id、组id、文件大小、最后访问时间、文件名;这些都在stat结构体里面、stat结构体以下:数组

/*用不到的成员被注释掉,只需了解须要的成员便可*/
struct stat{
    //dev_t st_dev;/*设备id号*/
    //ino_t st_ino;/*i节点号*/
    mode_t st_mode;/*权限与文件类型*/
    nlink_t st_nlink;/*硬连接数*/
    uid_t st_uid;/*用户id*/
    ggid_t st_gid;/*所在组id*/
    //dev_t st_rdev;/*设备id,对于特殊文件才有*/
    off_t st_size;/*大小,较为经常使用*/
    //blksize_t st_blocks;/*blocksize for file system I/O*/
    //blkcnt_t st_blksize;/*number of 512B blocks allocated*/
    //time_t st_atime;/*最后的访问时间*/
    time_t st_mtime;/*最后的修改时间,较为经常使用*/
    //time_t st_ctime;/*最后的状态改变时间*/
}

这个题目我的以为有些技巧性,首先是9个权限位信息,那么就要想到mode的权限管理,那么,上课所讲的mode_t mode哦按段文件类型的宏函数、表示文件权限与类型的宏变量就是不可少的:socket

S_ISREG(m)  is it a regular file?/*判断是不是普通文件*/
    S_ISDIR(m)  directory?/*判断是不是目录*/
    S_ISCHR(m)  character device?/*判断是不是字符设备*/
    S_ISBLK(m)  block device?/*判断是不是块设备*/
    S_ISFIFO(m) FIFO (named pipe)?/*判断是不是管道文件*/
    S_ISLNK(m)  symbolic link? (Not in POSIX.1-1996.)/*判断使是不是符号连接(软链接)*/
S_ISSOCK(m) socket? (Not in POSIX.1-1996.)/*判断是不是SOCKET文件*/

另外就是时间,要充分利用<time.h>里面的tm结构体,注意到最后利用localtime进行转换。函数

2.源码

#include<sys/types.h>
#include<sys/stat.h>
#include<time.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<dirent.h>
#include<unistd.h>
#include<pwd.h>
#include<grp.h>

/**
m:mode权限,这个请看前面解释
str:
*/
char* get_mode(mode_t mode,char* str)//显示文件读写权限函数
{
   if(S_ISREG(mode))
   	strcpy(str,"-");//普通文件
   else if(S_ISDIR(mode))
   	strcpy(str,"d");//目录文件
   else if(S_ISCHR(mode))
   	strcpy(str,"c");//字符设备文件
   else if(S_ISBLK(mode))
   	strcpy(str,"b");//块设备文件
   else if(S_ISFIFO(mode))
   	strcpy(str,"p");//管道文件
   else if(S_ISLNK(mode))
   	strcpy(str,"l");//连接文件
   else if(S_ISSOCK(mode))
   	strcpy(str,"n");//socket文件

   /**断定文件访问权限的屏蔽字
   这里使用strcat的巧妙之处就在于联想到是到最后字符串,那么这里将所需的权限按照顺序拼接,只需对比,那么就能够输出这里是否有访问的权限
  思路来源:leetcode中的题解*/
   // 属主权限
   strcat(str,mode&S_IRUSR?"r":"-");//判断是否用户可读
   strcat(str,mode&S_IWUSR?"w":"-");//判断用户是否可写
   strcat(str,mode&S_IXUSR?"x":"-");//判断用户有无执行权限

   // 同组权限
   strcat(str,mode&S_IRGRP?"r":"-");//判断组有无读权限
   strcat(str,mode&S_IWGRP?"w":"-");//判断组有无写特权
   strcat(str,mode&S_IXGRP?"x":"-");//判断组有无可执行权限

   // 其它权限
   strcat(str,mode&S_IROTH?"r":"-");//判断其余有无读权限
   strcat(str,mode&S_IWOTH?"w":"-");//判断其余我有无写权限
   strcat(str,mode&S_IXOTH?"x":"-");//判断其余有无写权限

   return str;//返回拼接完成的字符串,即为要求的9位字符串
}
/**
这里须要明确
一是Unix时间是从1970年1月1日0时0分0秒开始,用秒差形式,那么在结构体stat中有time_t st_time(最后修改时间)做为标准来进行打印

二是在c语言中,<time.h>有来判断时间tm结构体,计算机大多数状况使用的都是time_t,由于他的效率高,可是显示位tm结构形式,localtime()实现time_t到tm的转换,time_t的指针做为参数,返回值tm的指针
思路来源:学校acm题库
*/
void time_ch(struct stat *message)//经过秒数来计算日期
{
  struct tm * chtm = localtime(&(message->st_mtime));//这个在上面注释中已经详细说明,再也不赘述
  if(chtm == NULL){
    printf("localtime is error");
    exit(0);
  }
  else{
    printf("%d月 %d ",chtm->tm_mon+1,chtm->tm_mday);//tm_mom属于[0,11]
  }
  if(chtm->tm_hour < 10)//0-9要转换成0x形式
     printf("0");//先打印0
  printf("%d:",chtm->tm_hour);//在打印x
  printf("%d ",chtm->tm_min);//打印分钟不存在0x问题
  //对比ls -l,没有秒
}
void list_nlink(const struct stat *message){//打印出硬链接数
  printf("%d ",message->st_nlink);
}
/**
对于main里面参数的理解
* argc: 整数,为传给main()的命令行参数个数。
* argv: 字符串数组。
* env: 安符串数组。env[] 的每个元素都包含ENVVAR=value形式的字符串。其中ENVVAR为环境变量如PATH或87。value 为ENVVAR的对应值如C:\DOS,C:\TURBOC(对于PATH)或YES(对于87)。
*/
int main(int argc,char** argv,char** environ)//主函数
{
   char* dir_name=NULL;//文件名字
   if(argc == 1)//第一个参数,那么按道理来说,他应该是根目录(我的的猜想,没有获得验证)
   {
   	dir_name=".";
   } 
   else if(argc == 2)//第二个参数,即为文件
   {
   	dir_name = argv[1];//获取文件名字
   }
   else//当位3或者更大时,那么已经不是一个文件,退出程序
   {
   	puts("it isn't a dir");
   	return -1;
   }
   DIR* fd = opendir(dir_name);//打开文件
   if(NULL == fd)//判断错误并处理
   {
   	perror("opendir");
   	return -1;
   }
   struct dirent* de=readdir(fd);//定义接收readdir函数返回的结构体变量,判断是读取文件
   for(;de;de=readdir(fd))//
   {
   	if('.'==de->d_name[0]) continue;
   	//经过文件名得到文件信息
   	struct stat s;
   	int ret = lstat(de->d_name,&s);//用lstat函数读取filename文件的信息,并将结果返回到stat结构体中
   	if(0 > ret)//stat函数出错进行信息输出
   	{
   		perror("stat is error");
   		return -1;
   	}//stat函数不出错则进行信息输出
   	char str[11] = {};//用于9个标志位所需
   	printf("%s ",get_mode(s.st_mode,str));//类型
        list_nlink(&s);
   	struct passwd *passwd;
   	passwd = getpwuid(s.st_uid);
   	printf ("%s ", passwd->pw_name);//主名
   	struct group *group;
   	group = getgrgid(passwd->pw_gid);
   	printf ("%s ", group->gr_name); //组名
   	printf("%5lu ",s.st_size);//大小
   	time_ch(&s);//时间
   	printf("%s\t",de->d_name);//文件名
   	printf("\n");
   }
   closedir(fd);//关闭文件
}

3.测试

测试结果

进行测试,发现了本身其中的不足,没有排序以及没有总用量,而且没有对与在使用的打亮。若是有解决的,欢迎指正。测试

相关文章
相关标签/搜索