IO进程线程day3(2023.7.31)

一、Xmind整理:

文件描述符概念:

IO进程线程day3(2023.7.31)_第1张图片

二、课上练习:

练习1:用fread和fwrite实现文件拷贝 

#include 
#include 
#include 
#include 
int main(int argc, const char *argv[])
{
	//以读的方式打开源文件
	FILE* fp_r=fopen("./01_fopen.c","r");
	if(NULL==fp_r)
	{
		ERR_MSG("fopen");
		return -1;
	}
    //以写的方式打开源文件
	FILE* fp_w=fopen("./copy.c","w");
	if(NULL==fp_w)
	{
		ERR_MSG("fopen");
		return -1;
	}

	//读一次写一次,直到文件读取完毕
	char buf[128]="";
	size_t res=0;
	while(1)
	{
		bzero(buf,sizeof(buf));
		//以128为单位,读取1个数据,所当不足128的时候
		//剩下的数据读取不出来,所以这个代码是错误的
		res=fread(buf,1,sizeof(buf),fp_r);
		printf("res=%ld\n",res);
		if(0==res)
			break;
		fwrite(buf,1,res,fp_w);
	}
	printf("拷贝完毕\n");

	//关闭
	fclose(fp_w);
	fclose(fp_r);


	return 0;
}

IO进程线程day3(2023.7.31)_第2张图片

练习2:time

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

原型:

 #include 
 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);

练习3:localtime

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

原型:

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

          };

例题: 

#include 
#include 
#include 
#include 
#include 
int main(int argc, const char *argv[])
{
	/*
	time_t t=time(NULL);
	printf("%ld\n",t);

	time _t pt;
	time(&pt);
	printf("%d\n",pt);
	*/
	time_t t;
	struct tm* info=NULL;

	while(1)
	{
		t=time(NULL);
		info=localtime(&t);
		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);
		fflush(stdout);
		sleep(1);
	}

	return 0;
}

IO进程线程day3(2023.7.31)_第3张图片

练习4:文件描述符的总量

#include 
#include 
#include 
#include 
int main(int argc, const char *argv[])
{
	printf("%d %d %d\n",stdin->_fileno,stdout->_fileno,stderr->_fileno);
	FILE*fp=NULL;
	while(1)
	{
		fp=fopen("./1.txt","w");
		if(NULL==fp)
		{
			ERR_MSG("fopen");
			return -1;
		}
		printf("%d ",fp->_fileno);
		fflush(stdout);
	}
	return 0;
}

IO进程线程day3(2023.7.31)_第4张图片

IO进程线程day3(2023.7.31)_第5张图片

练习5: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      若文件不存在,则创建一个普通文件。
 若有多个选项合成一个打开方式,则用按位或连接:
     "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进行组合。

IO进程线程day3(2023.7.31)_第6张图片 

练习6:umask

the mode of the created file is (mode & ~umask).

文件创建时候的真实权限是 mode & ~umask

mode: 0777 -> 111 111 111 umask?111 111 101=> ~umask -> umask = 000 000 010 = 0002

结果: 0775 ----> 111 111 101

i. umask是什么

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

ii. 获取umask的值

终端输入:umask

iii. 修改umask的值

1.终端输入: umask 0 只在设置终端有效

2.umask()函数

 #include 
 #include 
 mode_t umask(mode_t mask);
 umask(0);

练习7:close

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

原型:

#include 
int close(int fd);

参数:

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

返回值:

成功,返回0;
失败,返回-1,更新errno;

练习8:write

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

原型:

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

参数:

int fd:指定要将数据写入到哪个文件中,填对应的文件描述符;
void *buf:指定要输出的数据的首地址,可以是任意类型数据;
size_t count:指定要输出的数据字节数;

返回值:

成功,返回成功输出的字节数;
失败,返回-1,更新errno;

 例题: 创建一个权限是0777的文件,并在数据写入到文件中

#include 
#include 
#include 
#include 
int main(int argc, const char *argv[])
{
	//将本程序的umask的值修改成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");

	ssize_t res=0;
	char buf[]="hello world";
	res=write(fd,buf,sizeof(buf));
	printf("res=%ld\n",res);

	if(close(fd)<0)
	{
		ERR_MSG("close");
		return -1;
	}
	printf("close success\n");
	return 0;
}

IO进程线程day3(2023.7.31)_第7张图片

注意: 

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

练习9:read

功能:从文件中读取数据

原型:

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

参数:

int fd:指定要从哪个文件中读取数据,填对应的文件描述符;
void *buf:指定要将读取到的数据存储到那块空间中,可以是任意类型数据;
size_t count:指定要读取的数据字节数;

返回值:

 >0, 成功,返回成功读取的字节数;
 =0, 文件读取完毕;
 =-1, 失败,返回-1,更新errno;

 例题1: read的使用

#include 
#include 
#include 
#include 
int main(int argc, const char *argv[])
{
	//将本程序的umask的值修改成0
	umask(0);
	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));
		/***************************************/
		//由于后续打印的是使用%s打印,所以需要保留一个\0位置
		//防止%s打印的时候越界少\0位 
		res=read(fd,buf,sizeof(buf)-1);
		if(0==res)
		{
			break;
		}
		printf("%s",buf);    //%s打印直到遇到\0位置
	}
#endif
	printf("读取完毕\n");
	if(close(fd)<0)
	{
		ERR_MSG("close");
		return -1;
	}
	printf("close success\n");

	return 0;
}

IO进程线程day3(2023.7.31)_第8张图片

 例题2:用read和write函数实现,拷贝图片

 提示:1.ls-l查看图片类型

            2.eog  图片--->打开图片

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

	ssize_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;
	}
	if(close(fd_w)<0)
	{
		ERR_MSG("close");
		return -1;
	}

	printf("close success\n");
	return 0;
}

IO进程线程day3(2023.7.31)_第9张图片

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

例题:lseek的使用 

#include 
#include 
#include 
#include 
int main(int argc, const char *argv[])
{
	//以读的方式打开源文件
	int fd_r=open("./1.png",O_RDONLY);
	if(fd_r<0)
	{
		ERR_MSG("open");
		return -1;
	}
	//计算文件大小
	off_t size=lseek(fd_r,0,SEEK_END);
	printf("size=%ld\n",size);
	//关闭
	close(fd_r);
	return 0;
}

IO进程线程day3(2023.7.31)_第10张图片

注意: 

若偏移量在文件开头,能否继续往前偏移 ---> 不行

若偏移量在文件结尾,能否继续往后偏移 ---> 可以

练习11:获取文件属性

IO进程线程day3(2023.7.31)_第11张图片

练习12:stat

功能:获取文件的属性

原型:

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

提取文件的权限:

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

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

IO进程线程day3(2023.7.31)_第12张图片

例题:文件权限提取 

#include 
#include 

void get_filePermission(mode_t m)   //mode_t m = buf.st_mode
{
    if((m & 0400) != 0)
        putchar('r');
    else
        putchar('-');

    if((m & 0200) != 0)                                      
        putchar('w');
    else
        putchar('-');

    if((m & 0100) != 0)
        putchar('x');
    else
        putchar('-');

    ///
    if((m & 0040) != 0)
        putchar('r');
    else
        putchar('-');

    if((m & 0020) != 0)
        putchar('w');
    else
        putchar('-');

    if((m & 0010) != 0)
        putchar('x');
    else
        putchar('-');
    

    if((m & 0004) != 0)
        putchar('r');
    else
        putchar('-');

    if((m & 0002) != 0)
        putchar('w');
    else
        putchar('-');

    if((m & 0001) != 0)
        putchar('x');
    else
        putchar('-');

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

    //文件的硬链接数
    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;
}

IO进程线程day3(2023.7.31)_第13张图片

三、课后作业:

1.用read函数计算文件的大小 

#include 
#include 
#include 
#include 
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 c;
	ssize_t res = 0;
	int count = 0;
	lseek(fd,0,SEEK_SET);
	while(1)
	{
		res = read(fd,&c,1);
		if(0 == res)
			break;
		count++;
	}
	printf("count=%d\n",count);

	if(close(fd) < 0)
	{
		ERR_MSG("close");
		return -1;
	}
	printf("close success\n");

	return 0;
}

IO进程线程day3(2023.7.31)_第14张图片

2.将课上的文件权限提取修改成循环方式

#include 
#include 

void get_filePermission(mode_t m)
{
	long x=0400;
	char c[]="rwx";
	int count=0;
	while(x)
	{
		if((m & x) != 0)
			putchar('r');
		else
			putchar('-');
		x=x>>1;
		if((m & x) != 0)                                      
			putchar('w');
		else
			putchar('-');
		x=x>>1;
		if((m & x) != 0)
			putchar('x');
		else
			putchar('-');
		x=x>>1;
	}

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

    //文件的硬链接数
    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;
}

IO进程线程day3(2023.7.31)_第15张图片

你可能感兴趣的:(算法)