用文件IO,实现ls -l的效果——stat及相关函数的使用

首先展示ls -l的表现效果

 无视最上面的总用量,我们可以看出,我们需要输出:文件类型、文件权限、硬链接数、当前用户名,当前用户组,文件大小,文件最后创建时间(月日、时分)以及文件名

为了实现功能,我们需要大量头文件

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

首先打开目录,我们采用外部传参的方式

//打开目录
	DIR *dp = opendir(argv[1]);
	if(NULL == dp)
	{
		printf("line%d,目录打开失败", __LINE__);
		perror("opendir");
		return -1;
	}
	

定义指针rp,用来获取读取到的目录信息

struct dirent *rp = NULL;
//指针原型:struct dirent *readdir(DIR *dirp);

目录中可能有不止一个文件,所以用死循环包裹住。用指针rp接收目录信息,以为ls -l无法显示隐藏信息,所以我们还需要摘除隐藏信息(隐藏信息以 ' . ' 开头)

rp = readdir(dp);     
		//判断文件读完还是出错
		if(NULL == rp)
		{
			if(0 == errno)   //目录读到结尾
			{
				break;
			}
			else
			{
				printf("line:%d", __LINE__);
				perror("readdir");
				return -1;
			}
		}
		if(rp->d_name[0] == '.')//筛掉隐藏文件
			continue;

至此,我们就成功筛选出了符合条件的信息

定义结构体变量buf,接收目录内的文件信息

struct stat buf;   //接受文件信息
//struct stat *statbuf:该指针指向的内存空间中会存储获取到的文件属性;

struct stat结构体的原型如下

struct stat *statbuf:该指针指向的内存空间中会存储获取到的文件属性;
返回值:
    成功,返回0;
    失败,返回-1,更新errno;
           struct stat {
               dev_t     st_dev;         /* ID of device containing file */
               ino_t     st_ino;         /* Inode number */
               mode_t    st_mode;        /* File type and mode */ 		文件类型以及文件权限
               nlink_t   st_nlink;       /* Number of hard links */ 	硬链接数
               uid_t     st_uid;         /* User ID of owner */ 		用户的uid
               gid_t     st_gid;         /* Group ID of owner */ 		组用户的gid
               dev_t     st_rdev;        /* Device ID (if special file) */
               off_t     st_size;        /* Total size, in bytes */ 	文件大小
               blksize_t st_blksize;     /* Block size for filesystem I/O */
               blkcnt_t  st_blocks;      /* Number of 512B blocks allocated*/

               /* Since Linux 2.6, the kernel supports nanosecond
                  precision for the following timestamp fields.
                  For the details before Linux 2.6, see NOTES. */

               struct timespec st_atim;  /* Time of last access */ 	文件最后一次访问的时候
               struct timespec st_mtim;  /* Time of last modification */ 文件最后一次被修改的时间
               struct timespec st_ctim;  /* Time of last status change */ 最后一次改变状态的时间(创建时间)

           #define st_atime st_atim.tv_sec      /* Backward compatibility */
           #define st_mtime st_mtim.tv_sec
           #define st_ctime st_ctim.tv_sec
           };

因为stat要的是文件以及路径,但rp->neme只有文件名。故,如果输入的文件不在当前路径下,stat将无法获取文件信息,所以,我们定义一个字符串数组来添加路径。

char pathname[99];
strcpy(pathname, argv[1]);
strcat(pathname, rp->d_name);

获取文件,以为stat函数要的是指针变量,如果我们采用的是结构体指针,则需要malloc手动事情空间,故,我在上面采用了结构体普通变量的方式,来偷懒。

//用地址规避malloc偷懒
		if( stat(pathname, &buf) < 0 )
		{
			printf("文件获取失败\n");
			perror("stat");
			return -1;
		}
		

1:文件类型获取

与文件权限在一个变量内存储:mode_t    st_mode;

man手册内介绍了一个自带函数

mode_t m;
m = buf.st_mode;  //给m赋值
get_fileType(m);  //文件类型 
//mode_t    st_mode;        /* File type and mode */ 		文件类型以及文件权限
int get_fileType(mode_t m)   //man手册自带函数
{

	switch (m & S_IFMT)
	{
	case S_IFBLK:  printf("b");        break;
	case S_IFCHR:  printf("c");        break;
	case S_IFDIR:  printf("d");        break;
	case S_IFIFO:  printf("p");        break;
	case S_IFLNK:  printf("l");        break;            
	case S_IFREG:  printf("-");        break;
	case S_IFSOCK: printf("s");        break;
	default:       printf("unknown?\n");   break;
	}
	return 0;

}

2:文件权限

文件权限在变量内表现为一个二进制数

000 000 000,分别代表wrxwrxwrx,所以,当,我们拿100 000 000去和给定的权限值按位与,如果第一位不是1,则结果为0,自然,我们就知道了,第一个位置:写权限,是没有的。我们拿一个循环包裹,让1一位一位移动,就可以直到每一个权限的情况

自定义函数:

void get_permission(mode_t m)
{
	int i=0;
	for(i=8; i>=0; i--)
	{
		if( (m & (1<<i)) == 0)  //求出对应位置是0还是1
		{
			printf("-");
			continue;
		}
		
		//能运行到当前位置则说明相应位置不为0
		switch(i%3)
		{
		case 2:
			printf("r");
			break;
		case 1:                                              
			printf("w");
			break;
		case 0:
			printf("x");
			break;
		}
	}
	return ;
}

3:硬链接数

//硬链接数
printf(" %ld ", buf.st_nlink);

4:当前用户名

采用自带函数:getpwuid()函数

函数原型:struct passwd *getpwuid(uid_t uid);

//当前用户
		struct passwd *pwd = NULL;
		pwd = getpwuid(buf.st_uid);
		if(NULL == pwd)
		{
			printf("getpwuid failed\n");
			return -1;
		}
		printf("%s ",pwd->pw_name);
		

5:当前用户组

//文件所属组用户名
		struct group *gp = NULL;
		gp = getgrgid(buf.st_gid);
		if(NULL == gp)
		{
			printf("getgrgid failed\n");
			return -1;
		}
		printf("%s ",gp->gr_name);

6:文件大小

//文件大小
printf("%8ld", buf.st_size);

7:时间

使用buf.st_ctime

使用自定义函数,函数上篇文章写过了,略加修改即可

//时间
void my_time(long ctime)
{
	long n = ctime;
	struct tm *m = localtime(&n);
	printf("%2d月  %d  %d:%d ",m->tm_mon+1, m->tm_mday, m->tm_hour, m->tm_min);
}

最后是文件名

//文件名
		printf("%s", rp->d_name);

再手动换行

不要忘记关闭目录

以下是完整代码

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


int main(int argc, const char *argv[])
{
	//打开目录
	DIR *dp = opendir(argv[1]);
	if(NULL == dp)
	{
		printf("line%d,目录打开失败", __LINE__);
		perror("opendir");
		return -1;
	}
	struct dirent *rp = NULL;

	while(1)
	{
		rp = readdir(dp);     
		//判断文件读完还是出错
		if(NULL == rp)
		{
			if(0 == errno)   //目录读到结尾
			{
				break;
			}
			else
			{
				printf("line:%d", __LINE__);
				perror("readdir");
				return -1;
			}
		}
		if(rp->d_name[0] == '.')//筛掉隐藏文件
			continue;
		
		//处理符合条件的文件
		struct stat buf;   //接受文件信息
		//因为stat要的是文件以及路径,但rp->neme只有文件名
		//故,如果输入的文件不在当前路径下,stat将无法获取文件信息
		//所以,我们定义一个字符串数组来添加路径
		char pathname[99];
		strcpy(pathname, argv[1]);
		strcat(pathname, rp->d_name);
		//用地址规避malloc偷懒
		if( stat(pathname, &buf) < 0 )
		{
			printf("文件获取失败\n");
			perror("stat");
			return -1;
		}
		
		//文件类型
		mode_t m;
		m = buf.st_mode;  //给m赋值
		get_fileType(m);  //文件类型 
		//文件权限
		get_permission(m);
		//硬链接数
		printf(" %ld ", buf.st_nlink);
		//当前用户
		struct passwd *pwd = NULL;
		pwd = getpwuid(buf.st_uid);
		if(NULL == pwd)
		{
			printf("getpwuid failed\n");
			return -1;
		}
		printf("%s ",pwd->pw_name);
		
		//文件所属组用户名
		struct group *gp = NULL;
		gp = getgrgid(buf.st_gid);
		if(NULL == gp)
		{
			printf("getgrgid failed\n");
			return -1;
		}
		printf("%s ",gp->gr_name);

		//文件大小
		printf("%8ld", buf.st_size);
   
		//时间
		my_time(buf.st_ctime);
		
		//文件名
		printf("%s", rp->d_name);

		printf("\n");
	}
	
	
	
	
	//关闭目录
	closedir(dp);
	return 0;
}

函数部分

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



int get_fileType(mode_t m)   //man手册自带函数
{

	switch (m & S_IFMT)
	{
	case S_IFBLK:  printf("b");        break;
	case S_IFCHR:  printf("c");        break;
	case S_IFDIR:  printf("d");        break;
	case S_IFIFO:  printf("p");        break;
	case S_IFLNK:  printf("l");        break;            
	case S_IFREG:  printf("-");        break;
	case S_IFSOCK: printf("s");        break;
	default:       printf("unknown?\n");   break;
	}
	return 0;

}
void get_permission(mode_t m)
{
	int i=0;
	for(i=8; i>=0; i--)
	{
		if( (m & (1<<i)) == 0)  //求出对应位置是0还是1
		{
			printf("-");
			continue;
		}
		
		//能运行到当前位置则说明相应位置不为0
		switch(i%3)
		{
		case 2:
			printf("r");
			break;
		case 1:                                              
			printf("w");
			break;
		case 0:
			printf("x");
			break;
		}
	}
	return ;
}

//时间
void my_time(long ctime)
{
	long n = ctime;
	struct tm *m = localtime(&n);
	printf("%2d月  %d  %d:%d ",m->tm_mon+1, m->tm_mday, m->tm_hour, m->tm_min);
}

//

头文件:略

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老K殿下

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值