實現「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.測試

測試結果

進行測試,發現了本身其中的不足,沒有排序以及沒有總用量,而且沒有對與在使用的打亮。若是有解決的,歡迎指正。測試

相關文章
相關標籤/搜索