0731|IO进程线程day3(标准IO函数3+文件IO函数)

目录

一、思维导图

二、标准IO函数(时间相关的函数)

2.1 time

2.2 localtime

练习:利用time和localtime循环显示时间

三、文件IO函数

3.1 文件描述符

3.1.1 概念

 3.1.2 特殊的文件描述符

3.1.3 文件描述符的总量

3.2 文件IO的函数

1) open

练:创建一个权限为777的文件

2) umask

练:用umask函数 创建一个权限为777的文件

3) close

4) write

练:将字符串写入文件中

5) read

练1:用read和write函数实现 拷贝文件到终端(两种方法)

练2:用read和write函数实现 拷贝图片

6) lseek

练1:用lseek函数 计算文件大小

练2:用read函数 计算文件大小

3.3 获取文件属性

1)stat

2)提取文件的权限

练:文件权限提取 并打印

三、作业

 3.1 【read】计算文件大小

3.2 【使用循环】文件权限提取并打印


一、思维导图

二、标准IO函数(时间相关的函数)

2.1 time

功能:从1970-1-1日至今的秒数;
原型:

    #include <time.h>

    time_t time(time_t *tloc);

参数:

        time_t *tloc:若不为空,则1970-1-1日至今的秒数同样会被存储到该指针指向的内存空间中;

返回值:

        成功,返回1970-1-1日至今的秒数;

        失败,返回((time_t) -1),更新errno;

使用方式:

    time_t t = time(NULL);  
    printf("%ld\n", t);

    time_t pt;                     
    time(&pt);
    printf("%ld\n", pt);

2.2 localtime

功能:将1970-1-1日至今的秒数转换成日历格式;

原型:

    #include <time.h>

    struct tm *localtime(const time_t *timep);

参数: time_t *timep: 指定要转换成日历格式的秒数的首地址;

返回值:

        成功,返回结构体指针; vi -t tm可以查看struct tm 成员 或者man手册往下翻

        失败,返回NULL;更新errno;

结构体成员:

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) */   一年中的第几天
};

练习:利用time和localtime循环显示时间

#include <stdio.h>
#include <head.h>
#include <time.h>
int main(int argc, const char *argv[])
{
	time_t t=0;
	struct tm* info=NULL;
	while(1)
	{
		t = time(NULL);
		info = localtime(&t);
		printf("%d-%02d-%0d %02d:%02d:%02d\r", \
				info->tm_year+1900, info->tm_mon+1, info->tm_mday, \
				info->tm_hour, info->tm_min, info->tm_sec);
		fflush(stdout);

		sleep(1);
	}
	return 0;
}

三、文件IO函数

注意点:

  1. 文件IO是不带缓冲区的
  2. 文件IO函数是由操作系统提供的,与操作系统绑定,又称之为系统调用。
  3. 标准IO是通过流指针维护一个文件,文件IO是通过文件描述符来维护一个文件。

3.1 文件描述符

3.1.1 概念

  1. 尝试打开一个文件的时候,系统会自动给这个文件分配一个编号,用这个编号来描述这个文件。这个编号就是文件描述符。
  2. 文件描述符的本质:数组下标。在main函数启动前,操作系统会帮助我们在用户空间创建一个数组(文件描述符表),且容量默认为1024. 范围是[0, 1023]
  3. 文件描述符申请原则:从小到大依次遍历,直到遇到没有被使用的文件描述符

 3.1.2 特殊的文件描述符

特殊的流指针

特殊的文件描述符

FILE* stdin

stdin->_fileno

0

FILE* stdout

stdout->_fileno

1

FILE* stderr

stderr->_fileno

2

3.1.3 文件描述符的总量

默认是1024个

  1. 循环打开不关闭,直到超出打开上限,得到文件描述符总量。
  2. getdtablesize()函数:获取操作系统的文件描述符总量。 printf("%d\n", getdtablesize());

3.2 文件IO的函数

open     /     close
read     /     write
lseek

1) open

功能:打开一个文件;

原型:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
       
  
    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    若文件不存在,则创建一个普通文件。

        

        若有多个选项合成一个打开方式,则用按位或连接:

        "w":O_WRONLY | O_CREAT | O_TRUNC

        mode_t mode:用来指定文件创建的时候的权限,例如:0664

        若flags中包含了O_CREAT或者O_TMPFILE的时候,就必须写mode参数;

        若flags没有O_CREAT或者O_TMPFILE的时候,会忽略mode参数;

返回值:

        成功,返回文件描述符,

        失败,返回-1,更新errno;

标准IO中的 r r+ w w+ a a+,用文件IO中的flags进行组合。

   ┌─────────────┬───────────────────────────────┐
   │fopen() mode │ open() flags                  │
   ├─────────────┼───────────────────────────────┤
   │     r       │ O_RDONLY                      │
   ├─────────────┼───────────────────────────────┤
   │     w       │ O_WRONLY | O_CREAT | O_TRUNC  │
   ├─────────────┼───────────────────────────────┤
   │     a       │ O_WRONLY | O_CREAT | O_APPEND │
   ├─────────────┼───────────────────────────────┤
   │     r+      │ O_RDWR                        │
   ├─────────────┼───────────────────────────────┤
   │     w+      │ O_RDWR | O_CREAT | O_TRUNC    │
   ├─────────────┼───────────────────────────────┤
   │     a+      │ O_RDWR | O_CREAT | O_APPEND   │
   └─────────────┴───────────────────────────────┘

练:创建一个权限为777的文件

 输入0777

结果为0775

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <head.h>
int main(int argc, const char *argv[])
{
	int fd = open("./open.txt", O_WRONLY|O_CREAT|O_TRUNC,0777);//出现775
	if(fd <0)
	{
		ERR_MSG("open");
		return -1;
	}
	printf("open success\n");
	return 0;
}

2) umask

i)umask是什么?

文件权限掩码,目的就是影响文件创建时候的权限。可以通过设置umask的值保证某些用户肯定没有某些权限。

ii)获取umask的值

终端输入:umask

iii)修改umask的值

  1. 终端输入: umask 0 只在设置终端有效
  2. umask()函数
    #include <sys/types.h>
    #include <sys/stat.h>
    
        mode_t umask(mode_t mask);
           
        umask(0);

练:用umask函数 创建一个权限为777的文件

输入0777

结果为0777

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <head.h>
int main(int argc, const char *argv[])
{	
    //将本程序的umake的值改为0
	umask(0);
	int fd = open("./open.txt", O_WRONLY|O_CREAT|O_TRUNC,0777);
	if(fd <0)
	{
		ERR_MSG("open");
		return -1;
	}
	printf("open success\n");
	
	if(close(fd) < 0)
	{
		ERR_MSG("close");
		return -1;
	}
	printf("关闭成功\n");
	return 0;
}

3) close

功能:关闭文件; 释放文件描述符;

原型:

       #include <unistd.h>

       int close(int fd);

参数: int fd:指定要关闭的文件描述符;

返回值:

        成功,返回0;

        失败,返回-1,更新errno;

	//关闭文件
	if(close(fd) < 0)
	{
		ERR_MSG("close");
		return -1;
	}

4) write

功能:将数据写入到文件中;

原型:

       #include <unistd.h>

       ssize_t write(int fd, const void *buf, size_t count);

参数:

         int fd:指定要将数据写入到哪个文件中,填对应的文件描述符;

        void *buf:指定要输出的数据的首地址,可以是任意类型数据;

        size_t count:指定要输出的数据字节数;

返回值:

        成功,返回成功输出的字节数;

        失败,返回-1,更新errno;

注意:write函数指定写多少个字节,就会从内存中拿多少个字节,写入到文件中,即使越界

练:将字符串写入文件中

#include <stdio.h>
#include <head.h>
int main(int argc, const char *argv[])
{
	//将本程序的umake的值改为0
	umask(0);
	//以w的形式打开
	int fd = open("./open.txt", O_WRONLY|O_CREAT|O_TRUNC,0777);
	if(fd <0)
	{
		ERR_MSG("open");
		return -1;
	}
	printf("open success\n");

	ssize_t res = 0;
	char buf[20]= "hello world";

	res = write(fd, buf, sizeof(buf));
	printf("res = %ld\n", res);

	if(close(fd) < 0)
	{
		ERR_MSG("close");
		return -1;
	}
	printf("关闭成功\n");
	return 0;
}

5) read

功能:从文件中读取数据;

原型:

       #include <unistd.h>

       ssize_t read(int fd, void *buf, size_t count);

参数:

        int fd:指定要从哪个文件中读取数据,填对应的文件描述符;

        void *buf:指定要将读取到的数据存储到那块空间中,可以是任意类型数据;

        size_t count:指定要读取的数据字节数;

返回值:

        >0, 成功,返回成功读取的字节数;

        =0, 文件读取完毕;

        =-1, 失败,返回-1,更新errno;

练1:用read和write函数实现 拷贝文件到终端(两种方法)

#include <stdio.h>
#include <head.h>
int main(int argc, const char *argv[])
{
	//将本程序的umake的值改为0
	umask(0);
	//以a的形式打开
	int fd = open("./01_fileno.c", O_RDONLY);
	if(fd <0)
	{
		ERR_MSG("open");
		return -1;
	}
	printf("open success\n");

	ssize_t res = 0;
	char buf[128]= "";
	while(1)
	{
		bzero(buf,sizeof(buf));
		res = read(fd, buf, sizeof(buf));
		if(0 == res)
		{
			break;
		}

		//将数据写入到终端,写的个数为实际读取到的字节数
		write(1, buf, res);
	}

#if 0
	while(1)
	{
		bzero(buf,sizeof(buf));
		res = read(fd, buf, sizeof(buf)-1);
		if(0 == res)
			break;
		printf("%s", buf);
	}

	printf("拷贝完毕\n");
#endif

	//关闭文件
	if(close(fd) < 0)
	{
		ERR_MSG("close");
		return -1;
	}
	printf("关闭成功\n");
	return 0;
}

练2:用read和write函数实现 拷贝图片

用read和write函数实现,拷贝图片。

        提示ls -l 查看图片类型

        eog 图片 ---- >打开图片

思路:

  1. ls-l查看图片类型
  2. 打开两个文件
  3. 读一次写一次拷贝
  4. 关闭文件
  5. eog +图片名.png 【打开图片】
#include <stdio.h>
#include <head.h>
int main(int argc, const char *argv[])
{
	//以读的方式打开源文件
	int fd_r=open("1.png",O_RDONLY);
	if(fd_r < 0)
	{
		ERR_MSG("open");
		return -1;
	}
	printf("open success\n");

	//以写的方式打开目标文件
	int fd_w=open("2.png",O_WRONLY |  O_CREAT | O_TRUNC, 0664);
	if(fd_w < 0)
	{
		ERR_MSG("open");
		return -1;
	}
	printf("open success\n");

	size_t res =0;
	char buf[128]= "";
	//读一次写一次
	while(1)
	{
		bzero(buf,sizeof(buf));
		res = read(fd_r, buf, sizeof(buf));
		if(0 == res)
			break;
		//读多少个就写几个
		if(write(fd_w, buf, res) <0)
		{
			ERR_MSG("write");
			return -1;
		}
	}
	printf("拷贝成功\n");

	//关闭源文件
	if(close(fd_r)<0)
	{
		ERR_MSG("close");
		return -1;
	}
	printf("fd_r关闭成功\n");
	//关闭目标文件
	if(close(fd_w)<0)
	{
		ERR_MSG("close");
		return -1;
	}
	printf("fd_w关闭成功\n");

	return 0;
}

 ​​​

6) lseek

功能:修改文件偏移量;

原型:

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

       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_r, 0, SEEK_END);
    printf("size=%ld\n", size);

练1:用lseek函数 计算文件大小

#include <stdio.h>
#include <head.h>
int main(int argc, const char *argv[])
{
	//以读的方式打开源文件
	int fd=open("1.png",O_RDONLY);
	if(fd < 0)
	{
		ERR_MSG("open");
		return -1;
	}
	printf("open success\n");

	off_t size = lseek(fd, 0, SEEK_END);
	printf("size=%ld\n", size);

	//关闭
	if(close(fd)<0)
	{
		ERR_MSG("close");
		return -1;
	}
	printf("关闭成功\n");
	return 0;
}

练2:用read函数 计算文件大小

#include <stdio.h>
#include <head.h>
int main(int argc, const char *argv[])
{
	//以读的方式打开源文件
	int fd=open("1.png",O_RDONLY);
	if(fd < 0)
	{
		ERR_MSG("open");
		return -1;
	}
	printf("open success\n");

	//偏移到文件结尾
	off_t size = lseek(fd, 0, SEEK_END);
	printf("size=%ld\n", size);
	char buf[128] = "";
	ssize_t count=0, res=0;

	//将偏移量移到文件开头
	lseek(fd, 0,SEEK_SET);	
	//读一次记一次
	while(1)
	{
		bzero(buf, sizeof(buf));
		res = read(fd, buf, sizeof(buf));
		if(0 == res)
			break;
		count+=res;
	}
	printf("count=%ld\n",count);
	
	//关闭
	if(close(fd)<0)
	{
		ERR_MSG("close");
		return -1;
	}
	printf("关闭成功\n");
	return 0;
}

3.3 获取文件属性

1)stat

功能:获取文件的属性;

原型:

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

       int stat(const char *pathname, struct stat *statbuf);

参数:

        char *pathname:指定要获取属性的文件路径以及名字;

        struct stat *statbuf:存储获取到的属性;

返回值:

        成功,返回0;

        失败,返回-1,更新errno;

结构体成员:

vi -t stat 或者 man手册往下翻

struct stat {
    	
        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

		off_t     st_size;        /* Total size, in bytes */     文件大小


		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
};

2)提取文件的权限

mode_t st_mode 本质上是一个unsigned int类型,里面存储了文件的类型和权限。

st_mode中其中低9bits存储了文件的权限:[0bit - 8bit]

mode: 0100664 ---> rw-rw-r--
        664----> 110 110 100 ---> 0664
                 100 000 000 ---> 0400
                 ------------
                 100 000 000 ===> 0400结果不等于0,需要打印'r'。否则打印'-'
                 
        664----> 110 110 100 ---> 0664
                 010 000 000 ---> 0200
                 ------------
                 010 000 000 ===> 0200结果不等于0,需要打印'w'。否则打印'-'
                 
        664----> 110 110 100 ---> 0664
                 001 000 000 ---> 0100
                 ------------
                 000 000 000 ===> 0000结果等于0,需要打印'-'。否则打印'x'

练:文件权限提取 并打印

#include <stdio.h>
#include <head.h>
void get_filePermission(mode_t m)
{
	if(m & 0400)	
		putchar('r');
	else
		putchar('-');				
	if(m & 0200)	
		putchar('w');
	else
		putchar('-');
	if(m & 0100)	
		putchar('x');
	else
		putchar('-');
///
	if(m & 0040)	
		putchar('r');
	else
		putchar('-');
	if(m & 0020)	
		putchar('w');
	else
		putchar('-');
	if(m & 0010)	
		putchar('x');
	else
		putchar('-');
/
	if(m & 0004)	
		putchar('r');
	else
		putchar('-');
	if(m & 0002)	
		putchar('w');
	else
		putchar('-');
	if(m & 0001)	
		putchar('x');
	else
		putchar('-');

}
int main(int argc, const char *argv[])
{
	struct stat buf;
	if(stat("./01_fileno.c",&buf) < 0 )
	{
		ERR_MSG("stat");
		return -1;
	}

	//文件的类型和权限
	printf("mode:0%o\n", buf.st_mode);
	get_filePermission(buf.st_mode);
	putchar(10);
	//文件的硬链接数
	printf("link:%ld\n", buf.st_nlink);
	//文件的所属用户
	printf("uid:%d\n", buf.st_uid);
	//文件所属组用户
	printf("gid:%d\n", buf.st_gid);
	//文件大小
	printf("size:%ld\n", buf.st_size);
	//文件的修改时间
	printf("time:%ld\n", buf.st_ctime);
	//文件的名字
	
	return 0;
}

三、作业

 3.1 【read】计算文件大小

#include <stdio.h>
#include <head.h>
int main(int argc, const char *argv[])
{
	//以读的方式打开源文件
	int fd=open("1.png",O_RDONLY);
	if(fd < 0)
	{
		ERR_MSG("open");
		return -1;
	}
	printf("open success\n");

	//偏移到文件结尾
	off_t size = lseek(fd, 0, SEEK_END);
	printf("size=%ld\n", size);
	char buf[128] = "";
	ssize_t count=0, res=0;

	//将偏移量移到文件开头
	lseek(fd, 0,SEEK_SET);	
	//读一次记一次
	while(1)
	{
		bzero(buf, sizeof(buf));
		res = read(fd, buf, sizeof(buf));
		if(0 == res)
			break;
		count+=res;
	}
	printf("count=%ld\n",count);
	
	//关闭
	if(close(fd)<0)
	{
		ERR_MSG("close");
		return -1;
	}
	printf("关闭成功\n");
	return 0;
}

3.2 【使用循环】文件权限提取并打印

方法一:

void get_filePermission(mode_t m)
{
	char buf[]="rwx";
	for(int i=0;i<9;i++)
	{
		if( (m & (0400)>>i) == 0)
		{
			putchar('-');
			continue;
		}
		printf("%c",buf[i%3]);
	}
	putchar(10);
}

方法二:

void get_filePermission(mode_t m)
{
	char buf[]="rwx";
	for(int i=0;i<9;i++)
	{
		if( (m & (0400)>>i) == 0)
		{
			putchar('-');
			continue;
		}
		switch(i%3)
		{
		case 0:putchar('r');break;
		case 1:putchar('w');break;
		case 2:putchar('x');break;
		}
	}
	putchar(10);
}

方法三:

思路:

  1. 需要打印的权限共分为3组,可通过进制右移取得一组的结果
  2. 循环三次即可得出3组的结果
  3. 详细参考2.9的get_filePermission函数
#include <stdio.h>
#include <head.h>
void get_filePermission(mode_t m)
{
	int i=0;
	mode_t mask=0400;
	for(i=0;i<3;i++)   //共三组
	{
		if(m & mask)
			putchar('r');
		else
			putchar('-');
		mask >>= 1;    //右移一位
		
		if(m & mask)
			putchar('w');
		else
			putchar('-');
		mask >>= 1;    //右移一位

		if(m & mask)
			putchar('x');
		else
			putchar('-');
		mask >>= 1;    //右移一位
	}
}
int main(int argc, const char *argv[])
{
	struct stat buf;
	if(stat("./01_fileno.c",&buf) < 0 )
	{
		ERR_MSG("stat");
		return -1;
	}

	//文件的类型和权限
	printf("mode:0%o\n", buf.st_mode);
	get_filePermission(buf.st_mode);
	putchar(10);
	//文件的硬链接数
	printf("link:%ld\n", buf.st_nlink);
	//文件的所属用户
	printf("uid:%d\n", buf.st_uid);
	//文件所属组用户
	printf("gid:%d\n", buf.st_gid);
	//文件大小
	printf("size:%ld\n", buf.st_size);
	//文件的修改时间
	printf("time:%ld\n", buf.st_ctime);
	//文件的名字
	
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值