IO学习系列之使用文件IO的接口在一个目录下,实现Linux命令“ls -l”的功能

  • 实例要求:
  • 使用文件IO的接口在一个目录下,实现Linux命令“ls -l”的功能;
  • 实例分析:
  • 正常使用“ls -l”命令,会出现以下内容:
/*
 -    rwxrw-rw-                                1          linux      linux          26                10月2 14:31    x.txt
文件类型  所属用户的权限\所属组的权限\其他人的权限 硬链接个数  所属用户    所属组      大小(字节)       时间戳       文件名
*/
  • 相关的文件IO接口函数如下:
  • opendir函数:
	 #include 
	 #include 
	 DIR *opendir(const char *name);
	 /*
	 功能:打开一个目录文件
	 
	 参数name:目录名
	 
	 返回值:
	 
    	成功:  目录指针
    	
    	失败:  NULL 重置错误码
     */
	 
  • readdir函数:
	 #include 
	 struct dirent *readdir(DIR *dirp);
	 /*
	 功能:读取目录下的内容
	 
	 参数:目录指针
	 
	 返回值:
	 
    	成功:  dirent结构体指针
    	
    	失败:  NULL  重置错误码
    */
    // dirent结构体指针
    struct dirent {
        ino_t          d_ino;       /* 读到的文件的inode号 */
        off_t          d_off;       /* 无需关注 */
        unsigned short d_reclen;    /* 这个结构体的大小 不是文件的大小 */
        unsigned char  d_type;      /* 文件类型 */
            DT_BLK      This is a block device.
            DT_CHR      This is a character device.
            DT_DIR      This is a directory.
            DT_FIFO     This is a named pipe (FIFO).
            DT_LNK      This is a symbolic link.
            DT_REG      This is a regular file.
            DT_SOCK     This is a UNIX domain socket.
        char           d_name[256]; /* 文件名 */
    };
	 
  • closedir函数:
	#include 
	#include 
	int closedir(DIR *dirp);
	/*
	功能:关闭一个目录
	
	参数dirp:目录指针
	
	返回值:
	
    	成功:  0
    	
    	失败:  -1  重置错误码
    */
	

  • stat函数:
	#include 
	#include 
	#include 
	int stat(const char *pathname, struct stat *statbuf);
	/*
	功能:
	
    	获取文件的属性信息
    	
	参数:
	
    	pathname:文件的路径和名字
    	
    	statbuf:用来保存文件属性的结构体
       
	返回值:
	
    	成功  0
    	失败  -1  重置错误码
	*/
	//文件属性的结构体
	 struct stat {
            dev_t     st_dev;         /* 文件所在磁盘的设备号 */
            ino_t     st_ino;         /* inode号 */
            mode_t    st_mode;        /* 文件的类型和访问模式 */
                //S_IFMT     0170000   文件类型的掩码
                //S_IFSOCK   0140000   socket
                //S_IFLNK    0120000   symbolic link
                //S_IFREG    0100000   regular file
                //S_IFBLK    0060000   block device
                //S_IFDIR    0040000   directory
                //S_IFCHR    0020000   character device
                //S_IFIFO    0010000   FIFO  
                if((S_IFMT & st_mode) == S_IFREG){//注意优先级问题
                    printf("普通文件\n");
                }
                //或者用下面的宏判断
                if(S_ISREG(m)){
                    printf("普通文件\n");
                }
                
                //st_mode & 0777 == 文件的权限
            nlink_t   st_nlink;       /* 硬链接的个数 */
            uid_t     st_uid;         /* 所属用户的id */
            gid_t     st_gid;         /* 所属组的id */
            dev_t     st_rdev;        /* 设备号 字符设备文件或者块设备文件使用 */
            off_t     st_size;        /* 总大小 单位字节 */
            blksize_t st_blksize;     /* 块的大小 */
            blkcnt_t  st_blocks;      /* 块的数量 */
            struct timespec st_atim;  /* 最后一次访问的时间 */
            struct timespec st_mtim;  /* 最后一次修改的时间 */
            struct timespec st_ctim;  /* 最后一次状态改变的时间 */
            //下面的宏定义是为了方便获取时间戳里的秒数的
            #define st_atime st_atim.tv_sec      /* Backward compatibility */
            #define st_mtime st_mtim.tv_sec
            #define st_ctime st_ctim.tv_sec
        };
  • getpwuid函数:
	#include 
    #include 
    struct passwd *getpwuid(uid_t uid);
    /*
	功能:
	
    	根据uid获取用户信息
    	
	参数:
	
    	uid: 用户id
    	
	返回值:
	
    	成功: 	用户信息结构体
    	
    	失败:  	NULL  重置错误码
	 */
	 //用户信息结构体
	 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 */
    };
    
  • getgrgid函数:
	 #include 
	 #include 
	 struct group *getgrgid(gid_t gid);
	 /*
	功能:
	
    	根据gid获取组信息
    	
	参数:
    	gid: 组id
    	
	返回值:
	
    	成功 组信息结构体
    	失败  NULL  重置错误码
    */
    struct group {
        char   *gr_name;        /* group name */
        char   *gr_passwd;      /* group password */
        gid_t   gr_gid;         /* group ID */
        char  **gr_mem;         /* NULL-terminated array of pointers to names of group members */
    };
	 
	 
  • sprintf函数:
	#include 
	int sprintf(char *str, const char *format, ...);
	/*
	功能:
	
    	将格式化的信息写入str指向的缓冲区中
    	
	参数:
	
    	str:		自定义的缓冲区的首地址
    	
    	format:	格式
    	
    	...:		可变参
    	
	返回值:
	
    	成功:  		格式化的字符的个数
    	
    	失败:  		小于0的值
    */
  • 示例代码:
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

//所属用户权限宏定义
#define U_R 0400
#define U_W 0200
#define U_X 0100

//所属组权限宏定义
#define G_R 0040
#define G_W 0020
#define G_X 0010

//其他人权限宏定义
#define O_R 0004
#define O_W 0002
#define O_X 0001

int main(int argc, const char *argv[])
{
    //入参合理性检查
    if (2 != argc)
    {
        printf("Usage : %s dir_name\n", argv[0]);
        return -1;
    }
    // 打开目录
    DIR *my_dir = opendir(argv[1]);
    if (NULL == my_dir)
    {
        perror("opendir error");
        return -1;
    }

    //文件的类型
    char type = '-';

    //所属用户权限赋初值
    char u_r = '-';
    char u_w = '-';
    char u_x = '-';

    //所属组权限赋初值
    char g_r = '-';
    char g_w = '-';
    char g_x = '-';

    //其他人权限赋初值
    char o_r = '-';
    char o_w = '-';
    char o_x = '-';

    int nlink = 0;

    char u_name[64] = {0};

    char g_name[64] = {0};

    int size = 0;

    char date[128] = {0};

    char path_name[512] = {0};



    struct tm *p = NULL;

    struct stat lk;

    struct dirent *dir = NULL;

    int mode = 0;
   
    

    while (NULL != (dir = readdir(my_dir)))
    {   
        //过滤隐藏文件
        if ('.' == *(dir->d_name))
        {
            continue;
        }


        //文件类型
        switch (dir->d_type)
        {
        
        
            case DT_BLK:
                type = 'b';
                break;

            case DT_SOCK:
                type = 's';
                break;

            case DT_FIFO:
                type = 'p';
                break;

            case DT_REG:
                type = '-';
                break;

            case DT_LNK:
                type = 'l';
                break;

            case DT_CHR:
                type = 'c';
                break;

            case DT_DIR:
                type = 'd';
                break;
            
       
        
        }

        //数组清零
        memset(path_name, 0, sizeof(path_name));


        //组装路径
        sprintf(path_name, "%s/%s", argv[1], dir->d_name);


        if (stat(path_name, &lk))
        {
            perror("stat error");
            return -1;
        }

        u_r = '-';
        u_w = '-';
        u_x = '-';

        
        g_r = '-';
        g_w = '-';
        g_x = '-';


        o_r = '-';
        o_w = '-';
        o_x = '-';


        // 文件权限
        mode = lk.st_mode & 0777;


        if (mode & U_R)
        {
            u_r = 'r';
        }
        if (mode & U_W)
        {
            u_w = 'w';
        }
        if (mode & U_X)
        {
            u_x = 'x';
        }


        if (mode & G_R)
        {
            g_r = 'r';
        }
        if (mode & G_W)
        {
            g_w = 'w';
        }
        if (mode & G_X)
        {
            g_x = 'x';
        }



        if (mode & O_R)
        {
            o_r = 'r';
        }
        if (mode & O_W)
        {
            o_w = 'w';
        }
        if (mode & O_X)
        {
            o_x = 'x';
        }

        //硬链接的个数
        nlink = lk.st_nlink;

        //所属用户名
        strcpy(u_name, getpwuid(lk.st_uid)->pw_name);


        //所属组名
        strcpy(g_name, getgrgid(lk.st_gid)->gr_name);

        //文件的大小(字节)
        size = lk.st_size;

        //时间戳(最后一次修改的时间)
        p = localtime(&(lk.st_mtime));

        sprintf(date, "%2d月%2d %02d:%02d", p->tm_mon + 1, \
                        p->tm_mday, p->tm_hour, p->tm_min);

        //输出文件的基本内容
        printf("%c%c%c%c%c%c%c%c%c%c %d %s %s %7d %s %-s\n",\
               type, u_r, u_w, u_x, g_r, g_w, g_x, o_r, o_w, o_x, nlink,\
               u_name, g_name, size, date, dir->d_name);
    }

    // 关闭目录

    closedir(my_dir);

    return 0;
}
  • 运行结果:
linux@ubuntu:~$ ./a.out ./
-rw-rw-r-- 1 linux linux     730 101 22:44 k1.c
-rw-rw-r-- 1 linux linux      26 101 22:40 k2.txt
-rwxrwxr-x 1 linux linux   12984 102 19:31 a.out
-rw-rw-r-- 1 linux linux    4078 102 19:17 ls-l.c
drwxrwxr-x 2 linux linux    4096 102 18:59 k3
linux@ubuntu:~$ ls -l
总用量 32
-rwxrwxr-x 1 linux linux 12984 102 19:31 a.out
-rw-rw-r-- 1 linux linux   730 101 22:44 k1.c
-rw-rw-r-- 1 linux linux    26 101 22:40 k2.txt
drwxrwxr-x 2 linux linux  4096 102 18:59 k3
-rw-rw-r-- 1 linux linux  4078 102 19:17 ls-l.c
  • 本示例代码,仅供参考;

你可能感兴趣的:(IO学习系列,linux,c语言,文件IO)