用I/O编程实现ls-l命令功能

使用ls-l命令可以得到一个目录下的所有文件(隐藏文件除外)的详细信息。

例:

 使用ls-l得到的详细信息包括:

1.第一列 '-' 表示文件的类型,文件类型包括以下几种类型:

  1. (1)- 普通文件(图片,视频,音频, world文档, txt文档, c文件....)
  2. d目录文件(文件夹)
  3. c字符设备文件(驱动课程学习)
  4. b块设备文件(驱动课程学习)
  5. l链接文件(类似快捷方式- linux学习)
  6. p管道文件(进程时学习)
  7. s套接字文件(网络编程学习)

2.第二列9个字母表示文件使用权限,‘r’表示具有读的权限,‘w’表示具有写的权限,‘x’表示具有执行的权限,‘-’ 表示不具有该权限。前三个字母表示用户可使用的权限,第4~6个字母表示用户同组可使用的权限,第7~9个字母表示其他人可使用的权限。 

3.第三列数字表示文件的硬链接数,新建的普通文件硬链接数默认为1 。

4.第四列表示用户名。在linux系统中为多用户共用同一系统,该组字符串标识某一用户。

5.第五列表示用户所在的组。

6.第六列表示文件的大小。文件的大小是以 字节为单位计算的。

7.第七、八列表示文件修改的月份和日期。

8.第九列表示最后一次修改文件的具体时间。

9.第十列表示目录下所有文件的文件名。

使用I/O编程实现ls-l功能用到的函数:

1.打开目录--opendir()

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

   声明:   DIR *opendir(const char *name);
   参数:
       name:打开的目录名
   返回值:
       成功返回目录流指针,失败返回NULL;

2.读取目录项--readdir()

  #include <dirent.h>

    声明:  struct dirent *readdir(DIR *dirp);    
    参数:
        dirp:目录流指针
    返回值:
           成功返回一个目录项的相关结构体指针,失败或者没有目录项可读返回NULL

    结构体:

       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 */
                 char d_name[256]; /* Null-terminated filename */
           };

3.获取文件属性--lstat()

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

     声明:  int lstat(const char *pathname, struct stat *statbuf);

    参数:
       pathname:文件名
       statbuf:文件属性结构体首地址
    返回值:
       成功返回0,失败返回-1;

3.1文件类型的获取:

所需要的结构体:

struct stat:

struct stat {    
      nlink_t st_nlink; // 硬链接个数  
      uid_t st_uid; // 所有者用户ID 
      gid_t st_gid; // 所有者组ID  
      off_t st_size; // 总体尺寸,以字节为单位 
      blksize_t st_blksize; // 文件系统 I/O 块大小
      blkcnt_t st_blocks; // 已分配 512B 块个数
      time_t st_atime; // 上次访问时间 
      time_t st_mtime; // 上次更新时间 
      time_t st_ctime; // 上次状态更改时间 
 };

 struct tm {
               int tm_sec;    /* Seconds (0-60) */
               int tm_min;    /* Minutes (0-59) */
               int tm_hour;   /* Hours (0-23) */
               int tm_mday;   /* Day of the month (1-31) */
               int tm_mon;    /* Month (0-11) */
               int tm_year;   /* Year - 1900 */
    }

以下为st_mode域定义:

       S_IFMT 0170000 bit mask for the file type bit field   //文件类型位字段的位掩码

       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   //FIFO

st_mode -- 跟文件类型文件权限有关

st_mode & S_IFMT == 文件类型对应宏,则表示文件为对应类型
       
   文件权限:

             st_mode & 权限宏 == 宏本身  表示具有该权限
               

         S_IRUSR     00400   owner has read permission   //所有者拥有读取权限
           S_IWUSR     00200   owner has write permission   //所有者有写权限
           S_IXUSR     00100   owner has execute permission  //所有者拥有执行权限
           
           S_IRGRP     00040   group has read permission  //组有读取权限
           S_IWGRP     00020   group has write permission   //组有写权限
           S_IXGRP     00010   group has execute permission   //组有执行权限
           
           S_IROTH     00004   others have read permission   //其他人拥有读取权限
           S_IWOTH     00002   others have write permission   //其他人拥有写权限
           S_IXOTH     00001   others have execute permission  //其他人拥有执行权限

使用I/O编程所需代码:

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

int main(int argc, char *argv[])
{
    int ret = 0;
    struct dirent *info = NULL;
    struct stat buf;
    struct tm *t = NULL;
    struct passwd *p = NULL;
    struct group *g = NULL;

    DIR * dfp = opendir(".");    //打开目录
    if(dfp == NULL)
    {
        perror("opendir");
        return -1;
    }

    while((info = readdir(dfp)) != NULL)    //循环读取目录项 -- 得到文件名
    {
        if(info->d_name[0] != '.')    //不显示隐藏文件
        {
            
            ret = lstat(info->d_name, &buf);   //获取指定文件的属性
            if(ret < 0)
            {
                perror("lstat");
                return -1;
            }
            
            p = getpwuid(buf.st_uid);    //通过用户id得到用户名
            g = getgrgid(buf.st_gid);     // 通过用户组id得到用户组名

            switch(buf.st_mode & S_IFMT)   //得到文件类型  st_mode & 文件类型掩码 == 对应文件类型宏,则表示为该文件类型
            {
                case S_IFREG:
                    printf("-");  break;
                case S_IFDIR:
                    printf("d");  break;
            }
 
            int i = 0;
            for(i = 8; i >= 0; i--)  //获取文件权限  st_mode & 权限宏 == 宏本身  表示具有该权限
            {
                if(buf.st_mode & (1<<i))
                {
                    switch(i%3)
                    {
                        case 2:
                            printf("r"); break;
                        case 1:
                            printf("w");  break;
                        case 0:
                            printf("x");  break;
                    }
                }
                else
                {
                    printf("-");
                }
            }


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

            printf("%s  %s  ", p->pw_name, g->gr_name);  
    
            printf("%-8ld ", buf.st_size);  //得到文件大小

            t = localtime(&buf.st_mtime);   //将文件最后一次修改时间的秒数,转换为本地时间

            printf("%d  %d  %02d:%02d  ", t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min);
            printf("%s\n", info->d_name);   //打印文件名


        }


    }

    return 0;
} 

结果:

 初学者,有问题请指正!!


版权声明:本文为qq_59917494原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。