C语言实现Linux中的ls -l 命令

目录


                一、ls -l 功能详解

                二、获取文件类型、文件权限

         1、获取文件类型

         2、获取文件的权限

三、获取文件的链接数、所属用户、所属组

          1、获取链接数

          2、获取文件所属用户

          3,获取文件所属的组

四、获取文件的最后修改时间

         1、获取年份

         2、获取月份

         3、获取天数

         4、获取一天当中的时间

                五、输出文件名

一、ls -l 功能详解:

        如上第一行:第一列表示文件的类型、权限信息,文件类型有l(链接文件)s(套接字文件)p(管道文件)-(普通文件)b(块设备文件)c(字符设备文件)d(目录文件)七大类型,权限有用户/组用户/其他用户的(读)r、(写)w、(执行)x权限-(表示没有任何权限),这一列的第一个字符表示文件的类型,往后都是代表的不同用户的权限,权限位每隔3位为一个用户的权限第一个三位表示文件所有者的权限,如上文件类型为普通文件,文件所有者拥有r和w的权限,组用户拥有r和w的权限,而其他用户则只有r的权限

        第二列表示文件的链接数,第三列表示文件的所属用户, 第四列表示文件所属的组, 第五列表示文件的大小,第六列、第七列、第八列分别表示文件的最后修改时间的具体年份月份天数以及一天中的具体时间,第九列则为文件名本身

二、获取文件类型、文件权限:

        1、获取文件类型:

                此操作涉及到一个stat结构体

  struct stat {
               dev_t     st_dev;         /* ID of device containing file */
               ino_t     st_ino;         /* Inode number */
               mode_t    st_mode;        /* 表示文件的类型以及文件的权限 */
               nlink_t   st_nlink;       /* 文件的连接数 */
               uid_t     st_uid;         /* 文件所有者的uid号 */
               gid_t     st_gid;         /* 文件所属组的gid号 */
               dev_t     st_rdev;        /* Device ID (if special file) */
               off_t     st_size;        /*文件所占的空间大小*/
               blksize_t st_blksize;     /* Block size for filesystem I/O */
               blkcnt_t  st_blocks;      /* Number of 512B blocks allocated */

 S_IFMT     0170000   bit mask for the file type bit field          

           S_IFSOCK   0140000   套接字文件
           S_IFLNK    0120000   链接文件
           S_IFREG    0100000   普通文件
           S_IFBLK    0060000   块设备文件
           S_IFDIR    0040000   目录文件
           S_IFCHR    0020000   字符设备文件
           S_IFIFO    0010000   管道文件

                                                  以上为文件类型对应的宏定义(8进制表示)

        我们只需要将对应文件的stat里的st_mode与上面的S_IFMT进行一个&的操作,再与上面宏定义的文件类型相比较,如果为真则是对应的文件类型

	struct stat* buff=(struct stat*)malloc(sizeof(struct stat));//创建一个stat类型结构体指针并分配内存空间
	DIR* d1=opendir("./");                //创建一个目录流指针并用opendir()函数打开当前的目录
	if(d1==NULL) perror("open");           //如果打开失败,输出失败信息
	struct dirent*dir=readdir(d1);          //readdir()可以打开一个目录并读取第一个读到的文件
    stat(dir->d_name,buff);               //stat()函数可以将对应的文件名传进去保存在stat*buff里,后续通过buff里的成员变量访问文件相关信息

switch(buff->st_mode & S_IFMT){        //寻找对应的文件类型
		case S_IFSOCK:                   //如果是管道文件则打印s
			printf("s");                
			break;
		case S_IFLNK:                    //如果是链接文件则打印l
			printf("l");
			break;
		case S_IFREG:                    //如果是普通文件则打印-
			printf("-");
			break;
		case S_IFBLK:                    //如果是块设备文件则打印b
			printf("b");
			break;
		case S_IFDIR:                    //如果是目录文件则打印d
			printf("d");    
			break;
		case S_IFCHR:                    //如果是字符设备文件则打印c
			printf("c");
			break;
		case S_IFIFO:                    //如果是管道文件则打印p
			printf("p");
			break;
	}

        2、获取文件的权限:

                                                     文件权限对应的宏(同样也是8进制表示)

           S_IRUSR     00400   文件所有者读权限        //可以用st_mode&1 再左移8位判断是否有对应权限
           S_IWUSR     00200   文件所有者写权限        //可以用st_mode&1 再左移7位判断是否有对应权限
           S_IXUSR     00100   文件所有者执行权限      //可以用st_mode&1 再左移6位判断是否有对应权限
           
           S_IRGRP     00040   文件所属组读权限        //可以用st_mode&1 再左移5位判断是否有对应权限
           S_IWGRP     00020   文件所属组写权限        //可以用st_mode&1 再左移4位判断是否有对应权限
           S_IXGRP     00010   文件所属组执行权限      //可以用st_mode&1 再左移3位判断是否有对应权限

           S_IROTH     00004   其他用户读权限          //可以用st_mode&1 再左移2位判断是否有对应权限
           S_IWOTH     00002   其他用户写权限          //可以用st_mode&1 再左移1位判断是否有对应权限
           S_IXOTH     00001   其他用户执行权限        //可以用st_mode&1 再左移0位判断是否有对应权限

        通过以上左移的操作我们可以发现一个规律:st_mode&1后左移对应的位数,读权限是左移8、5、2位,他们对3取余数都等于2,写权限左移7、4、1位,他们对3取余数都等于1,执行权限左移6、3、0位,他们对3取余数都等于0

        我们可以先用对应文件的st_mode号与1进行与运算,然后再左移对应的位数(判断所属的用户是否有读写执行的权限,有则为真(值大于0,二进制表示)),如果有对应的权限则再进一步判断是哪一种权限(左移的位数对3取余数(余数为2则有读权限,为1则有写的权限,为0则有执行的权限)),如果值为假(st_mode&1<<对应的位数==0)则表示没有对应的权限

int n=8;
while(n >= 0)
	{
		if(statbuf->st_mode & 1 << n){   //判断是否有权限       
			switch(n % 3){               //判断rwx中的哪一种权限
				case 2:        
					printf("r");
					break;
				case 1:
					printf("w");
					break;
				case 0:
					printf("x");
					break;
			}
		}else{
			printf("-");                //没有权限
		}
		n--;
	}
	printf("  ");
}

        当然也可以用st_mode&1<<对应的位数与9中权限的宏相比较,但这样做会大大增加代码量,所以最好用这种方法

三、获取文件的链接数、所属用户、所属组:

        1、获取链接数:文件的链接数保存在stat结构体里面的st_nlink成员里面,可以直接输出他获取

        2、获取文件所属用户:文件所属用户的uid号保存在stat里面的st_uid成员里面,可以用getpwuid()函数将对应的uid号转换成对应的用户字符,用户字符保存在struct passwd里面的pw_name成员里面,所以要创建一个passwd的变量

        3,获取文件所属的组:gid号保存在stat里面的st_gid里面,可以用getpwuid()函数将对应的gid号转换成对应的用户字符,再输出pw_name 就可以了

struct passwd* ursname,*groupname;
ursname=(struct passwd*)malloc(sizeof(struct passwd));
ursname=getpwuid(buff->st_uid);
groupname=getpwuid(buff->st_gid);

四、获取文件的最后修改时间:

                                                                涉及到的时间结构体

struct tm {int tm_sec; /* 秒 – 取值区间为[0,59] */
int tm_min; /* 分 - 取值区间为[0,59] */
int tm_hour; /* 时 - 取值区间为[0,23] */
int tm_mday; /* 一个月中的日期 - 取值区间为[1,31] */
int tm_mon; /* 月份(从一月开始,0代表一月) - 取值区间为[0,11] */
int tm_year; /* 年份,其值等于实际年份减去1900 */
int tm_wday; /* 星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推 */
int tm_yday; /* 从每年的1月1日开始的天数 – 取值区间为[0,365],其中0代表1月1日,1代表1月2日,以此类推 */
int tm_isdst; /* 夏令时标识符,实行夏令时的时候,tm_isdst为正。不实行夏令时的进候,tm_isdst为0;不了解情况时,tm_isdst()为负。*/};

        1、获取年份:

                        stat结构体中的st_mtime保存的文件最后修改时间,用localtime()函数转换为对应的tm结构体,再访问tm中的tm_year

        2、获取月份:

                        访问tm中的tm_mon

        3、获取天数:

                        访问tm中的tm_yday

        4、获取一天当中的时间:

                        访问tm中的tm_hour(时),访问tm中的tm_min(分),访问tm中的tm_sec(秒)

struct tm* t;            //创建一个tm结构体
size_t t0;               //穿件一个size_t的变量用于接收st_mtime
t0=buff->st_mtime;
t=localtime(&t0);        //将stat里面的最后修改时间转换为tm类型保存起来 

五、输出文件名:

        将用readdir()函数获取文件流中的文件名保存在dirent结构体里面,然后直接输出dirent结构体里面的d_name即可

程序源码

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值