嵌入式养成计划-25-IO进线程----IO,时间相关函数,文件IO函数,文件属性相关函数,目录相关函数

接上文:上文:标准IO函数

一个小demo:Linux下使用C语言实现Linux的查看文件信息命令“ls -l”

Linux下使用C语言实现Linux的查看文件信息命令“ls -l”

六十、 IO

60.4 时间相关的函数

60.4.1 time

功能:
	获取1970-1-1至今的秒数;
原型:
	#include 
	time_t time(time_t *tloc);
参数:
	time_t *tloc:	若不为空,则会将获取到的秒数存储到该指针指向的内存空间;
					若填NULL,在该指针无效;
返回值:
	成功,返回秒数;
	失败,返回(time_t) -1;

60.4.2 localtime

功能:
	将1970-1-1至今的秒数,转换成日历格式;
原型:
	#include 
	struct tm *localtime(const time_t *timep);
参数:
	time_t *timep:指定要将哪个秒数转换成日历格式,填该变量的地址;
返回值:
	成功,返回结构体指针;
	失败,返回NULL,更新errno;

struct tm 结构体

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) */=tm_mon+1   
	int tm_year;   /* Year - 1900 */=tm_year+1900
	int tm_wday;   /* Day of the week (0-6, Sunday = 0) */	星期
	int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */	一年中的第几天
	int tm_isdst;  /* Daylight saving time */ 
};

60.4.3 自己写的时钟

#include 
#include 
#include 
#include 
#include 

int main(int argc, const char *argv[])
{
    //  清屏    system函数可以在C/C++中使用shell
    system("clear");
    //  定义时间结构体类型的变量,用于获取当前的秒数
    time_t t;
    //  用于根据当前的秒数得到当前的日期与时间
    struct tm *info = NULL;
    //  死循环进行显示日期时间
    while (1)
    {
        time(&t);                   //  获取秒数
        info = localtime(&t);       //  获取当前的日期时间存入结构体
        //  根据结构体内容进行输出  \r表示每次都回退输出的起始位置
        printf("%d-%02d-%02d %02d:%02d:%02d\r",
               info->tm_year + 1900, info->tm_mon + 1, info->tm_mday,
               info->tm_hour, info->tm_min, info->tm_sec);
        //  刷新标准输出stdout缓冲区,让缓冲区的数据输出
        fflush(stdout);
        //  休眠1秒
        sleep(1);
    }
    return 0;
}

60.5 文件IO函数

  1. 文件IO函数是由操作系统提供的基本IO函数,与操作系统绑定,不同操作系统之间文件IO函数不同,又称之为系统调用函数。
  2. 文件IO函数没有缓冲区!!
  3. 文件IO函数通过 文件描述符 来维护(操作)一个文件。

60.5.1 文件描述符

1. 文件描述符概念

  1. 文件描述符是一个整型数,其实是一个编号。每当打开一个文件的时候,操作系统会自动给这个文件编号,用这个编号来描述这个文件。
  2. 标准IO函数最终依然会调用对应操作系统提供的文件IO函数。标准IO函数是对文件IO函数的二次封装,在文件IO函数的基础上封装了一个缓冲区,同时将文件描述符也一起封装到了FILE结构体中。

简化的FILE结构体

struct _IO_FILE {
	
	char* _IO_buf_base;		/* Start of reserve area. */	缓冲区的起始地址
	char* _IO_buf_end;		/* End of reserve area. */	缓冲区的结束地址

	int _fileno;		文件描述符:文件IO时候讲解。
}
  1. 文件描述符的总量是1024个,范围是[0, 1023]。所以在不使用的情况下,需要关闭。
  2. 申请原则:每次申请都从小到大依次遍历。若小的文件描述符被占用,则继续遍历,直到遍历到没有被使用过的文件描述符,若前面有文件描述符被释放,也会从小到大开始检索使用

2. 文件描述符的本质

  • 本质:数组下标,即文件描述符表的下标。
    嵌入式养成计划-25-IO进线程----IO,时间相关函数,文件IO函数,文件属性相关函数,目录相关函数_第1张图片

3. 特殊文件描述符

特殊流指针 特殊文件描述符
FILE* stdin stdin->_fileno 0
FILE* stdout stdout->_fileno 1
FILE* stderr stderr->_fileno 2

4. 文件描述符总量计算

  • 循环打开文件不关闭
    #include 
    
    int main(int argc, const char *argv[])
    {
        printf("%d %d %d\n", stdin->_fileno, stdout->_fileno, stderr->_fileno);
        while(1)
        {
            FILE* fp = fopen("1.txt", "w");
            if(NULL == fp)
            {                                                                     
                perror("fopen");
                return -1;
            }
            printf("%d\n", fp->_fileno);
        }
    
        return 0;
    }
    
  • getdtablesize()函数
    功能:
    	获取当前程序能打开的最大文件描述符个数;
    原型:
    	#include 
    	int getdtablesize(void);
    使用:       
    	printf("size=%d\n", getdtablesize());
    

60.5.2 文件IO函数

open     /     close
write    /     read
lseek

1. open

功能:
	打开一个文件;
原型:
	#include 
	#include 
	#include 
	
	int open(const char *pathname, int flags);
	int open(const char *pathname, int flags, mode_t mode);
参数:
	char *pathname:指定要打开的文件路径以及名字;
	int flags:打开方式;
		O_RDONLY		只读, 
		O_WRONLY		只写, 
		O_RDWR			读写
	-----以上三种必须,且只能包含一种-----
		O_APPEND		追加方式
		O_TRUNC			清空,若文件存在,且文件是个普通文件,且以写的方式打开,会清空文件
		O_CREAT			若文件不存在,则创建一个普通文件;	
	mode_t mode:用于指定文件创建时候的权限。
		当flags中有O_CREAT或者O_TMPFILE的时候,mode参数必须提供权限。
		当flags中没有O_CREAT或者O_TMPFILE的时候,mode参数会被忽略;

返回值:
	成功,返回文件描述符;
	失败,返回-1,更新errno;

标准IO中的打开方式,分别对应上述文件IO中,flags的组合。

"r"		:	O_RDONLY
"r+"	:	O_RDWR				//	不是追加
"w"		:	O_WRONLY|O_TRUNC|O_CREAT
"w+"	:	O_RDWR|O_TRUNC|O_CREAT
"a"		:	O_WRONLY|O_APPEND|O_CREAT
"a+"	:	O_RDWR|O_APPEND|O_CREAT

2. umask

the mode of the cre‐ated  file  is  (mode & ~umask).
文件创建时候的权限是,mode & ~umask

具体运算情况:

mode & ~umask
mode : 0777 ----> 111 111 111
                & 111 111 101 == ~umask ===> umask= 000 000 010 = 0002
:0775       ----> 111 111 101
  1. umask : 文件权限掩码,影响文件创建时候的权限。
    1. 例如将umask的值设置为0002,则可以确保其他用户肯定没有写权限。
  2. 获取uamsk的值: 终端输入umask
  3. 修改umask的值
    1. 终端输入: umask 0 — 将umask清0 — 只在设置终端有效
    2. 用umask函数设置umask的值
      示例:
      #include 
      #include 
      	mode_t umask(mode_t mask);
      	umask(0);
      	umask(0002);
      

3. close

功能:
	关闭文件,释放文件描述符;
原型:
	#include 
	int close(int fd);
参数:
	int fd:指定要关闭的文件对应的文件描述符;
返回值:   
	成功,返回0;
	失败,返回-1,更新errno;

4. write

功能:
	将数据写入到指定文件中;
原型:
	#include 
	ssize_t write(int fd, const void *buf, size_t count);
参数:
	int fd:文件描述符;
	void *buf:指定要输出的数据的首地址; void*类型,可以输出任意类型数据;
	size_t count:指定要输出的字节数;
返回值:
	成功,返回成功输出的字节数;
	失败,返回-1,更新errno;

5. read

功能:
	从指定文件中读取数据; 遇到空格,\n字符不会停止读取
原型:
	#include 
	ssize_t read(int fd, void *buf, size_t count);
参数:
	int fd:文件描述符;
	void *buf:指定用于存储读取到的数据; void*类型,可以读取任意类型数据;
	size_t count:指定要读取的字节数;
返回值:
	>0, 成功读取到的字节数;
	=0, 文件读取完毕;
	=-1, 函数运行失败,更新errno;

嵌入式养成计划-25-IO进线程----IO,时间相关函数,文件IO函数,文件属性相关函数,目录相关函数_第2张图片

6. lseek

功能:
	修改文件偏移量,并获取修改后的位置距离开头的偏移量;
原型:
	#include 
	#include 
	off_t lseek(int fd, off_t offset, int whence);
参数:
	int fd:指定要修改哪个文件的偏移量,填对应的文件描述符;
	off_t offset:距离whence的偏移量,
					若想要往文件开头方向偏移,填负数, 
					若想往文件结尾方向偏移,填正数.
	int whence:
		SEEK_SET     文件开始位置, 
		SEEK_CUR     文件当前位置, 
		SEEK_END     文件结尾位置;
返回值:
	成功,返回修改后的位置距离开头的偏移量;
	失败,返回-1,更新errno;

计算文件大小:
	off_t size = lseek(fd, 0, SEEK_END);
	printf("size=%ld\n", size);          

60.6 文件属性相关函数

60.6.1 stat

功能:
	获取文件属性;
原型:
	#include 
	#include 
	#include 

	int stat(const char *pathname, struct stat *statbuf);
参数:
	char *pathname:文件的路径及文件名;
	struct stat *statbuf:存储获取到的属性;
返回值:
	成功,返回0;
	失败,返回-1,更新errno;

结构体 struct stat

struct stat {
	dev_t     st_dev;         /* ID of device containing file */
	ino_t     st_ino;         /* Inode number */                  //文件的inode号
	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
};

60.6.2 提取文件权限

mode: 0100664
mode_t    st_mode;  该成员变量中存储了文件的类型以及权限。
mode_t类型本质上是一个:unsigned int 
。st_mode变量的低9bits,存储了文件的权限。范围[8, 0]bit
664 ---> rw- rw- r--
        0664 ---> 110 110 100
                & 100 000 000
                --------------
                  100 000 000 ===> 结果不等于0,打印'r'

        0664 ---> 110 110 100
                & 010 000 000
                --------------
                  010 000 000 ===> 结果不等于0,打印'w' 
                  
        0664 ---> 110 110 100
                & 001 000 000
                --------------
                  000 000 000 ===> 结果等于0,打印'-' 

嵌入式养成计划-25-IO进线程----IO,时间相关函数,文件IO函数,文件属性相关函数,目录相关函数_第3张图片

60.6.3 提取文件类型

mode: 0100664
mode_t    st_mode;  该成员变量中存储了文件的类型以及权限。
mode_t类型本质上是一个:unsigned int 
  1. 通过宏函数提取;
    步骤:
    	man 2 stat ---->st_mode的解释意思:see inode(7)
    	man 7 inode		
    		S_ISREG(m)  is it a regular file?              '-'
    		
    		S_ISDIR(m)  directory?                         'd'
    		
    		S_ISCHR(m)  character device?                  'c'
    		
    		S_ISBLK(m)  block device?                      'b'
    		
    		S_ISFIFO(m) FIFO (named pipe)?                 'p'
    		
    		S_ISLNK(m)  symbolic link?  (Not in POSIX.1-1996.) 'l'
    		
    		S_ISSOCK(m) socket?  (Not in POSIX.1-1996.)        's'
    上述,若为该文件,则返回真。否则返回假。
    

嵌入式养成计划-25-IO进线程----IO,时间相关函数,文件IO函数,文件属性相关函数,目录相关函数_第4张图片

  1. 从st_mode中提取代表文件权限的bits
           S_IFMT     0170000   bit mask for the file type bit field
mode & s_IFMT
            mode:   0100664         ----> 001 000 000 110 110 100
            S_IFMT: 0170000         ----> 001 111 000 000 000 000
            --------------------------------------------------------
                                          001 000 000 000 000 000 ===> 0100000
计算后的结果,与下列宏进行比较,等于哪个就是哪个类型文件;  
           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

mode & s_IFMT
            mode:   040775          ----> 000 100 000 111 111 101
            S_IFMT: 0170000         ----> 001 111 000 000 000 000
            --------------------------------------------------------
                                          000 100 000 000 000 000 ===> 040000

嵌入式养成计划-25-IO进线程----IO,时间相关函数,文件IO函数,文件属性相关函数,目录相关函数_第5张图片

60.6.4 提取文件所属用户名

uid_t	st_uid;	 /* User ID of owner */ 	//文件所属用户的uid号

getpwuid函数

功能:根据提供的uid,转换成用户信息;
原型:
       #include 
       #include 

       struct passwd *getpwuid(uid_t uid);
参数:
    uid_t uid:指定要获取用户信息的uid号;
返回值:
    成功,返回非空;
    失败,返回NULL; 更新errno;
struct passwd {
	char   *pw_name;       /* username */         用户名
	char   *pw_passwd;     /* user password */    用户密码
	uid_t   pw_uid;        /* user ID */          uid
	gid_t   pw_gid;        /* group ID */         gid
	char   *pw_gecos;      /* user information */ 
	char   *pw_dir;        /* home directory */
	char   *pw_shell;      /* shell program */
};
struct passwd* pwd = getpwuid(buf.st_uid);
if(NULL == pwd)
{
	perror("getpwuid");
	return -1;
}
printf("usrname: %s\n", pwd->pw_name);

60.6.5 提取文件所属组用户名

gid_t	st_gid;		/* Group ID of owner */		//文件所属用户的gid号

getgrgid函数

功能:通过gid获取对应组的信息;
原型:
       #include 
       #include 


       struct group *getgrgid(gid_t gid);
参数:
    gid_t     st_gid:指定要获取哪个组用户信息,填对应的gid号;
返回值:
    成功,返回非空;
    失败,返回NULL; 更新errno;
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 */
};
struct group* grp = getgrgid(buf.st_gid);
if(NULL == grp)
{
	perror("getgrgid");
	return -1;
}
printf("grpname: %s\n", grp->gr_name);

60.7. 目录相关函数

60.7.1 opendir

功能:打开一个目录
原型:
       #include 
       #include 

       DIR *opendir(const char *name);
参数:
    char *name:指定要打开的目录的路径以及名字;
返回值:
    成功,返回非空;
    失败,返回NULL,更新errno;

60.7.2 closedir

功能:关闭目录;
原型:
       #include 

       #include 

       int closedir(DIR *dirp);
参数:
    DIR *dirp:指定要关闭哪个目录就填对应的指针;
返回值:
    成功,返回0;
    失败,返回-1,更新errno;

60.7.3 readdir

功能:读取目录;
原型:
       #include 

       struct dirent *readdir(DIR *dirp);
参数:
    DIR *dirp:指定要读取哪个目录,填目录对应的指针;
返回值:
    成功,返回非空
    失败,返回NULL,更新errno;
    目录读取完毕,返回NULL,不更新errno;0 == errno)
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 */
};

一个小demo:Linux下使用C语言实现Linux的查看文件信息命令“ls -l”

Linux下使用C语言实现Linux的查看文件信息命令“ls -l”

你可能感兴趣的:(c语言,c++,linux)