在Linux中我们会经常使用ls -l 这条命令来查看文件信息,但是这个命令到底是怎么实现的呢?下面我就带大家用C语言来实现ls -l 这条命令,直接上代码吧:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <dirent.h> #include <pwd.h> #include <grp.h> #include <time.h> // ls-l 功能函数,参数为一个文件名 void ls_l(char name[]) { // 定义一个stat类型的结构体 struct stat my_stat; int ret = stat(name,&my_stat); if (ret == -1){ perror("stat"); return ; } // 判断并打印文件类型 ,这里用到了很多函数调用,后面会为大家贴上这些函数的用法 if (S_ISDIR(my_stat.st_mode)) printf("d"); else if (S_ISBLK(my_stat.st_mode)) printf("b"); else if (S_ISCHR(my_stat.st_mode)) printf("c"); else if (S_ISLNK(my_stat.st_mode)) printf("l"); else if (S_ISSOCK(my_stat.st_mode)) printf("s"); else if (S_ISREG(my_stat.st_mode)) printf("-"); else if (S_ISFIFO(my_stat.st_mode)) printf("p"); // 判断文件的权限信息 printf("%c",(my_stat.st_mode) & (1<<8)?'r':'-'); printf("%c",(my_stat.st_mode) & (1<<7)?'w':'-'); printf("%c",(my_stat.st_mode) & (1<<6)?'x':'-'); printf("%c",(my_stat.st_mode) & (1<<5)?'r':'-'); printf("%c",(my_stat.st_mode) & (1<<4)?'w':'-'); printf("%c",(my_stat.st_mode) & (1<<3)?'x':'-'); printf("%c",(my_stat.st_mode) & (1<<2)?'r':'-'); printf("%c",(my_stat.st_mode) & (1<<1)?'w':'-'); printf("%c",(my_stat.st_mode) & (1<<0)?'x':'-'); // 打印链接数 printf(" %ld",my_stat.st_nlink); // 打印所属用户 struct passwd *uid = getpwuid(my_stat.st_uid); printf(" %s",uid->pw_name); // 打印所属组 struct group *gid = getgrgid(my_stat.st_gid); printf(" %s",gid->gr_name); // 打印文件大小 printf(" %-8ld",my_stat.st_size); // 打印时间 struct tm *t = localtime((time_t *)&my_stat.st_mtim); printf(" %d月 %d %d:%d ",t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min); // 打印文件名 printf("%-2s\n",name); } // 这里是使用命令行传参 int main(int argc, const char *argv[]) { //判断是否携带参数,如果没有携带参数,就默认为当前路径 if (argc == 1){ printf("请输入文件路径,或者文件名\n"); return -1; } struct stat my_stat; int ret = stat(argv[1],&my_stat); // 判断输入的是否为目录 if (S_ISDIR(my_stat.st_mode)){ // 如果为目录,我们将目录打开,把里面的内容(文件名)传给功能函数 DIR * dir = opendir(argv[1]); if (NULL == dir){ perror("opendir"); return -1; } struct dirent *p = readdir(dir); if (NULL == p) { perror("readdir"); return -1; } while (p!=NULL){ ls_l(p->d_name); p = readdir(dir); } closedir(dir); }else // 不是目录 ls_l(argv[1]); return 0; }
上述代码中用到了库函数和结构体,下面是一部分函数和结构体的具体内容:
struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* inode number */ mode_t st_mode; 文件的权限、文件的类型 /* protection */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; 所属用户ID /* user ID of owner */ gid_t st_gid; 所属组ID /* group ID of owner */ dev_t st_rdev; /* device ID (if special file) */ off_t st_size; 文件的大小 /* total size, in bytes */ blksize_t st_blksize; /* blocksize for filesystem I/O */ blkcnt_t st_blocks; /* number of 512B blocks allocated */ time_t st_atime; 最后一次访问时间 /* time of last access */ time_t st_mtime; 最后一次修改时间 /* time of last modification */ time_t st_ctime; 最后一次文件文件属性修改时间 /* time of last status change */ };
2.【将uid 转换为 用户名】
#include <sys/types.h> #include <pwd.h> struct passwd *getpwuid(uid_t uid); struct passwd { char *pw_name; /* username */ char *pw_passwd; /* user password */ uid_t pw_uid; /* user ID */ gid_t pw_gid; /* group ID */ char *pw_gecos; /* user information */ char *pw_dir; /* home directory */ char *pw_shell; /* shell program */ };
#include <sys/types.h> #include <grp.h> struct group *getgrgid(gid_t gid); struct group { char *gr_name; /* group name */ char *gr_passwd; /* group password */ gid_t gr_gid; /* group ID */ char **gr_mem; /* group members */ };
{ 常规文件:S_ISREG '-' 目录:S_ISDIR 'd' 字符设备:S_ISCHR 'c' 块设备:S_ISBLK 'b' 管道:S_ISFIFO 'p' 套接字:S_ISSOCK 's' 符号链接:S_ISLNK 'l' }
include <sys/types.h> #include <dirent.h> DIR *opendir(const char *name); /***************************************** *功能: 打开一个目录文件 *参数: @name 目录文件路径 *返回值: 成功 返回 目录流指针 * 失败 返回 NULL 更新 errno ******************************************/ #include <dirent.h> struct dirent *readdir(DIR *dirp); /***************************************** *功能: 读目录流指针 *参数: @dirp 目录流指针 *返回值: 成功 返回 struct dirent 指针 * 失败 返回 NULL 表示目录中的文件读完 ******************************************/ struct dirent { ino_t d_ino; /* inode number */ off_t d_off; /* not an offset; see NOTES */ unsigned short d_reclen; /* length of this record */ unsigned char d_type; /* type of file; not supported by all filesystem types */ char d_name[256]; /* filename */ }; #include <sys/types.h> #include <dirent.h> int closedir(DIR *dirp); /***************************************** *功能: 关闭目录流 *参数: @dirp 目录流指针 *返回值: 成功 返回 0 * 失败 返回 -1 更新 errno ******************************************/