Linux下使用C语言模拟ls -l命令(适合Linux初学者,附源码)

       最近学习了目录流,可从目录中获取该目录下各个文件的属性、文件类型、文件的权限等等内容。于是尝试在Linux下使用C语言模拟ls -l命令。

实现步骤:

一、打开目录

二、读取目录

三、获取文件属性

四、获取文件权限

五、获取文件链接数

六、获取用户名和组名

七、获取文件大小

八、获取文件最后修改时间  

九、获取文件名

十、关闭目录流


实现步骤:

一、打开目录

#include <sys/types.h>
#include <dirent.h>

DIR *opendir(const char *name){
    参数: 目录名
    返回值: 成功返回一个目录流指针,失败返回NULL;
}

二、读取目录

#include <dirent.h>
struct dirent *readdir(DIR *dirp){
    参数: dirp 目录流
    返回值: 成功返回下一个目录项,失败或者读到目录末尾返回NULL,并设置错误号
}

dirent结构体如下:

struct dirent {
               ino_t           d_ino;             /* Inode number */  索引节点编号
               off_t           d_off;               /* Not an offset; see below */  不是偏移;见下文 
               unsigned short  d_reclen;   /* Length of this record */  此记录的长度 
               unsigned char   d_type;      /* Type of file; not supported
                                                      by all filesystem types */ 以Null结尾的filenameType文件
               char            d_name[256];   /* Null-terminated filename */  以Null结尾的文件名
           };

主要使用d_name;

三、获取文件属性

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *pathname, struct stat *statbuf);
如果获取的文件是链接文件,那么获取的是符号链接文件的目标文件的相关属性

int fstat(int fd, struct stat *statbuf);
以文件描述符的方式来获取文件的属性


int lstat(const char *pathname, struct stat *statbuf);
如果获取的文件是链接文件,那么获取的是符号链接文件的本身的相关属性

返回值:成功返回0, 失败返回-1并设置错误号;

系统在stat.h中定义了相对应的带参宏,可以让我们快速判断文件类型 

S_ISREG(m)            是否是一个常规文件
S_ISDIR(m)              是否是一个目录
S_ISCHR(m)            是否是一个字符设备
S_ISBLK(m)             是否是一个块设备
S_ISFIFO(m)           是否是一个FIFO文件
S_ISLNK(m)            是否是一个链接
S_ISSOCK(m)         是否是一个SOCKET文件

可使用 st_mode & 掩码 来得到 st_mode 中特定的部分
掩码的宏定义在 include <sys/stat.h>
#define S_IFMT 0170000 文件类型的位遮罩

st_mode & S_IFMT : 得到文件类型

struct stat statbuf;
	/*获取文件属性*/
switch(statbuf.st_mode & S_IFMT){
		case S_IFSOCK: printf("s");	break;    /*套接字文件*/
		case S_IFLNK:  printf("l"); break;    /*链接文件*/
		case S_IFREG:  printf("-");	break;    /*普通文件*/
		case S_IFBLK:  printf("b"); break;    /*块设备文件*/
		case S_IFDIR:  printf("d"); break;    /*目录文件*/
		case S_IFCHR:  printf("c"); break;    /*字符设备文件*/
		case S_IFIFO:  printf("p"); break;    /*管道文件*/
}

struct stat这个结构体是用来描述一个linux系统文件系统中的文件属性的结构。

struct stat {

        mode_t   st_mode;     //文件对应的模式,文件,目录等

        ino_t      st_ino;            //inode节点号

        dev_t      st_dev;          //设备号码

        dev_t      st_rdev;         //特殊设备号码

        nlink_t    st_nlink;         //文件的链接数

        uid_t      st_uid;            //文件所有者

        gid_t      st_gid;            //文件所有者对应的组

        off_t      st_size;           //普通文件,对应的文件字节数

        time_t     st_atime;       //文件最后被访问的时间

        time_t     st_mtime;      //文件内容最后被修改的时间

        time_t     st_ctime;       //文件状态改变时间

        blksize_t st_blksize;    //文件内容对应的块大小

        blkcnt_t   st_blocks;    //伟建内容对应的块数量

      };

四、获取文件权限

st_mode字段的低9位,代表文件的权限,标识了文件所有者(owner)、组用户(group)、其他用户(other)的读(r)、写(w)、执行(x)权限。

S_IRUSR      00400   owner has read permission                 8         100 000 000
S_IWUSR     00200   owner has write permission                 7         010 000 000
S_IXUSR      00100   owner has execute permission            6         001 000 000

S_IRGRP      00040   group has read permission                 5          000 100 000
S_IWGRP     00020   group has write permission                 4          000 010 000
S_IXGRP      00010   group has execute permission            3          000 001 000

S_IROTH      00004   others have read permission              2           000 000 100
S_IWOTH     00002   others have write permission              1           000 000 010
S_IXOTH      00001   others have execute permission         0           000 000 001

00001-->00400   即1往左移8位

/*获取文件权限*/
for(int n = 8; n >= 0; n--){
	if(statbuf.st_mode & (1 << n)){ //判断权限位的低9位 0-8
		switch(n % 3){
			case 2: printf("r"); break;
			case 1: printf("w"); break;
			case 0: printf("x"); break;
		}
	}else
		printf("-");

五、获取硬连接数

通过访问stat结构体中的st_nlink来获取文件链接数

printf("%ld ", statbuf.st_nlink); 

六、获取用户名和组名

使用getpwuid()函数

 #include <sys/types.h>
 #include <pwd.h>

struct passwd *getpwuid(uid_t uid);

// 结构体struct passwd如下
 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 */
           };

struct passwd *uidp = getpwuid(statbuf.st_uid);
struct passwd *gidp = getpwuid(statbuf.st_gid);
printf("%s %s " , uidp->pw_name, gidp->pw_name); 

七、获取文件大小

通过访问stat结构体中的st_size来获取文件大小

printf("%ld ",  statbuf.st_size); //获取文件大小

八、获取文件最后修改时间  

通过访问stat结构体中的st_mtime来获取文件最后修改时间,调用localtime转换成月 日,时 分

struct tm *tp;
ctime(&statbuf.st_mtime); //获取文件最后修改时间
tp = localtime(&statbuf.st_mtime);
printf("%2d月  %2d %2d:%2d ", 
            tp->tm_mon + 1,
			tp->tm_mday,
			tp->tm_hour,
			tp->tm_min);

九、获取文件名

通过访问dirent结构体中的d_name来获取文件名

printf("%s\n", dp->d_name); //文件名

十、关闭目录流

int closedir(DIR *dirp);
    返回值: 成功返回0, 失败返回-1,并设置错误号;

实现代码:

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

int main(int argc, char *argv[]) 
{
	if(argc != 2){
		printf("please input %s & a pathname\n", argv[0]);
		return -1;
	}
	DIR *dirp = opendir(argv[1]);
	if(NULL == dirp){
		perror("opendir");
		return -1;
	}

	struct dirent *dp; //创建目录流指针
	struct stat statbuf; 
	while(NULL != (dp = readdir(dirp))){
		if(dp->d_name[0] == '.'){ //排除隐藏文件
			continue;
		}
		else{
			/*如果为链接文件,获取的是链接文件的本身的相关属性*/
			if(-1 == lstat(dp->d_name, &statbuf)){
				perror("lstat");
				return -1;
			}

			/*获取文件属性*/
			switch(statbuf.st_mode & S_IFMT){
				case S_IFSOCK: printf("s");	break;
				case S_IFLNK:  printf("l"); break;
				case S_IFREG:  printf("-");	break;
				case S_IFBLK:  printf("b"); break;
				case S_IFDIR:  printf("d"); break;
				case S_IFCHR:  printf("c"); break;
				case S_IFIFO:  printf("p"); break;
			}

			/*获取文件权限*/
			for(int n = 8; n >= 0; n--){
				if(statbuf.st_mode & (1 << n)){
					switch(n % 3){
						case 2: printf("r"); break;
						case 1: printf("w"); break;
						case 0: printf("x"); break;
					}
				}else
					printf("-");
			}
			printf("%2ld ", statbuf.st_nlink); //获取文件链接数
			struct passwd *uidp = getpwuid(statbuf.st_uid);
			struct passwd *gidp = getpwuid(statbuf.st_gid);
			printf("%s %s " , uidp->pw_name, gidp->pw_name); //获取用户名、组名
			printf("%5ld ", statbuf.st_size); //获取文件大小

			struct tm *tp;
			ctime(&statbuf.st_mtime); //获取文件最后修改时间
			tp = localtime(&statbuf.st_mtime);
			printf("%2d月  %2d %2d:%2d ", 
					tp->tm_mon + 1,
					tp->tm_mday,
					tp->tm_hour,
					tp->tm_min);
		}
		printf("%s\n", dp->d_name); //文件名
	}
	closedir(dirp);
	return 0;
} 

实现效果:

 

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值