IO进程线程day4(2023.8.1)

一、Xmind整理:

进程的五态图:

 内存分布图:

 注:栈区:存储局部变量,形参(上边打错了!!!)

虚拟内存和物理内存:

进程的STAT:

二、课上练习:

练习1:将课上的文件权限提取修改成循环方式

#include <stdio.h>
#include <head.h>

void get_filePermission(mode_t m)
{
	//方法一:
	/*
	   for(int i=0;i<9;i++)
	   {
	   if((m&(0400>>i))==0)
	   {
	   putchar('-');
	   continue;
	   }
	//能运行到当前位置,则代表对应位置有权限
	//需要判断是r  w  x当中的哪一个
	switch(i%3)
	{
	case 0:putchar('r');break;
	case 1:putchar('w');break;
	case 2:putchar('x');break;
	}
	}
	*/

	//方法二:
	char buf[]="rwx";
	for(int i=0;i<9;i++)
	{
		if((m&(0400>>i))==0)
		{
			putchar('-');
			continue;
		}
		printf("%c",buf[i%3]);
	}
	return;
}
int main(int argc, const char *argv[])
{
	struct stat buf;
	if(stat("./2.png", &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;
}

练习2:提取文件的类型

mode_t    st_mode   本质上是一个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

若是该类型文件,则返回真,否则返回假
void get_fileType(mode_t m) 
{
    if(S_ISREG(m))
        putchar('-');

    else if(S_ISDIR(m))
        putchar('d');

    else if(S_ISCHR(m))
        putchar('c');       

    return ;

}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
void get_fileType(mode_t m)
{
	if(S_ISREG(m))
		putchar('-');
	else if(S_ISDIR(m))
		putchar('d');
	else if(S_ISCHR(m))
		putchar('c');
	else if(S_ISBLK(m))
		putchar('b');
	else if(S_ISFIFO(m))
		putchar('p');
	else if(S_ISLNK(m))
		putchar('l');
	else if(S_ISSOCK(m))
		putchar('s');

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

	//文件的类型和权限
	printf("mode: 0%o\n", buf.st_mode);
	get_fileType(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;
}

方法2: 
mode       0040775
S_IFMT     0170000   bit mask for the file type bit field

mode       0040775 ---> 000 100 000 111 111 101
S_IFMT     0170000 ---> 001 111 000 000 000 000  &
                    ------------------------------
                        000 100 000 000 000 000 ---> 040000

与下列宏进行比较,与哪个相同,就是对应类型文件
           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:      0100664 ---> 001 000 000 110 110 100
S_IFMT     0170000 ---> 001 111 000 000 000 000  &
                    ------------------------------
                        001 000 000 000 000 000 ---> 0100000
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
#include <time.h>
void get_fileType(mode_t m)
{
	switch(m&S_IFMT)
	{
	case S_IFSOCK:putchar('s');break;
	case S_IFLNK:putchar('l');break;
	case S_IFREG:putchar('-');break;
	case S_IFDIR:putchar('d');break;
	case S_IFCHR:putchar('c');break;
	case S_IFBLK:putchar('b');break;
	case S_IFIFO:putchar('p');break;
	}
	return;
}
int main(int argc, const char *argv[])
{
	struct stat buf;
	if(stat("./2.png", &buf) < 0)
	{
		ERR_MSG("stat");
		return -1;
	}

	//文件的类型和权限
	printf("0%o ", buf.st_mode);
	get_fileType(buf.st_mode);   
	//文件的硬链接数
	printf("%ld ", buf.st_nlink);

	//文件的所属用户
	printf("%d ", buf.st_uid);
	struct passwd* pwd=getpwuid(buf.st_uid);
	if(NULL==pwd)
	{
		ERR_MSG("getpwuid");
		return -1;
	}
	printf("%s ",pwd->pw_name);

	//文件所属组用户
	printf("%d ", buf.st_gid);
	struct group* grp=getgrgid(buf.st_gid);
	if(NULL==grp)
	{
		ERR_MSG("getgrgid");
		return -1;
	}
	printf("%s ",grp->gr_name);

	//文件大小
	printf("%ld ", buf.st_size);
	//文件的修改时间
	struct tm* info=NULL;
	info=localtime(&buf.st_mtime);
	//printf("%ld ",buf.st_ctime);
	printf("%02d %02d %02d:%02d ",info->tm_mon+1,info->tm_mday,info->tm_hour,info->tm_min);
	printf("2.png\n");

	return 0;
}

练习3:提取文件所属用户名

uid_t     st_uid;         /* User ID of owner */     用户的uid

getpwuid函数

功能:通过uid号获取用户的信息
原型:
 #include <sys/types.h>
 #include <grp.h>
 struct group *getgrgid(gid_t gid);
参数:
gid_t 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)
    {                                             
        ERR_MSG("getgrgid");
        return -1;
    }
    printf("%s\n", grp->gr_name);
完整代码示例: 
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <head.h>

//获取文件权限
void get_filePermission(mode_t m)   //mode_t m = buf.st_mode
{
    char buf[] = "rwx";

    for(int i=0; i<9; i++)
    {
        if( (m & (0400>>i)) == 0)
        {
            putchar('-');
            continue;
        }

        //能运行到当前位置,则代表对应位置有权限
        //需要判断是r w x中的哪一个                          
        /*
        switch(i%3)
        {
        case 0:
            putchar('r');
            break;
        case 1:
            putchar('w');
            break;
        case 2:
            putchar('x');
            break;
        }
        */

        printf("%c", buf[i%3]);

    }
    return;
}

//获取文件类型
void get_fileType(mode_t m)     //mode_t m = buf.st_mode
{
    switch(m & S_IFMT)
    {
    case S_IFSOCK: putchar('s');    break;
    case S_IFLNK: putchar('l');     break;
    case S_IFREG: putchar('-');     break;
    case S_IFDIR: putchar('d');     break;
    }

    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_fileType(buf.st_mode);
    get_filePermission(buf.st_mode);

    //文件的硬链接数
    //printf("link: %ld\n", buf.st_nlink);
    printf(" %ld", buf.st_nlink);

    //文件的所属用户
    //printf("uid: %d\n", buf.st_uid);
    //将uid转换成名字
    struct passwd* pwd = getpwuid(buf.st_uid);
    if(NULL == pwd)
    {
        ERR_MSG("getpwuid");
        return -1;
    }
    printf(" %s", pwd->pw_name);


    //文件所属组用户
    //printf("gid: %d\n", buf.st_gid);
    //将gid转换成名字
    struct group* grp = getgrgid(buf.st_gid);
    if(NULL == grp)
    {
        ERR_MSG("getgrgid");
        return -1;
    }
    printf(" %s", grp->gr_name);


    //文件大小
    //printf("size: %ld\n", buf.st_size);
    printf(" %ld", buf.st_size);

    //文件的修改时间
    printf(" time: %ld\n", buf.st_ctime);

    //文件的名字


    return 0;
}

练习4:opendir

功能:打开一个目录文件
原型:
 #include <sys/types.h>
 #include <dirent.h>
 DIR *opendir(const char *name);
参数:
 char *name:指定要打开的目录的路径以及名字;
返回值:
 成功,返回指针;
 失败,返回NULL,更新errno;

练习5:closedir

功能:关闭目录
原型:
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
返回值:
 成功,返回0;
 失败,返回-1,更新errno;

练习6:readdir

功能:读取目录
原型:
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
返回值:
 成功,返回结构体指针:
 失败,返回NULL; 更新errno;
 目录读取完毕,返回NULL,不更新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 */
           };


练习7:打印当前路径下所有文件的名字,除了隐藏文件

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
#include <dirent.h>
#include <errno.h>
int main(int argc, const char *argv[])
{
	DIR* dp=opendir("./");
	if(NULL==dp)
	{
		ERR_MSG("opendir");
		return -1;
	}
	printf("opendir success\n");
	int i=0;
	while(1)
	{
		struct dirent* rp=readdir(dp);
		if(NULL==rp)
		{
			if(0==errno)
			{
				printf("目录读取完毕\n");
				break;
			}
			else
			{
				ERR_MSG("readdir");
				return -1;
			}
		}
		//判断是否是隐藏文件:以.字符开头
		if(rp->d_name[0]!='.')   //*(rp->d_name)
			printf("[%d]%s\n",++i,rp->d_name);
	}
	if(closedir(dp)<0)
	{
		ERR_MSG("closedir");
		return -1;
	}

	return 0;
}

练习8:fork

功能:创建一个子进程
原型:
 #include <sys/types.h>
 #include <unistd.h>
 pid_t fork(void);
返回值:
  成功, >0 , 在父进程中,返回创建的子进程的pid号;
         =0,   在子进程中,返回0;
  失败,返回-1,更新errno,且没有子进程被创建
注意: 

1.fork函数创建的子进程,会克隆父进程用户空间的所有资源,以及PC寄存器的值。所以子进程不会运行执行过的fork函数以及fork函数以上的代码。

(ps :PC寄存器中存储着下一次该运行到哪一行代码)

2.父子进程的虚拟地址空间不是同一块,但是由于子进程是从父进程拷贝过来的,所以fork完毕的一瞬间,父子进程的用户空间长得完全一致

3.父子进程映射的物理地址不是同一块空间

   ①写时拷贝:当父子进程均不修改其中的内容的时候,此时映射的物理地址是同一块空间。若某个进程要修改其中的内容的时候,此时才会真正的申请一块新的物理地址空间给子进程的虚拟地址映射

例题:任务1:验证虚拟地址相不相同
           任务2:验证映射的物理地址相不相同 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
int main(int argc, const char *argv[])
{
	printf("__%d__\n",__LINE__);
	int a=10;
	//创建一个子进程
	pid_t cpid=fork();	//在fork以下的这段代码,父子进程均运行
	if(cpid>0)//在父进程中,该条件为真
	{
		a=20;
		printf("cpid=%d a=%d %p %d\n",cpid,a,&a,__LINE__);
	}
	else if(0==cpid)//在子进程中,该条件为真
	{
		sleep(1);//主动放弃CPU资源
		printf("cpid=%d a=%d %p %d\n",cpid,a,&a,__LINE__);
	}
	else
	{
		perror("fork");
		return -1;
	}
	while(1)
	{
		sleep(1);
	}

	return 0;
}

三、课后作业:

1.从终端获取一个文件的路径以及名字。

若该文件是目录文件,则将该文件下的所有文件的属性显示到终端,类似ls -l该文件夹

若该文件不是目录文件,则显示该文件的属性到终端上,类似ls -l这单个文件

#include <stdio.h>
#include <string.h>
#include <head.h> 
void get_fileType(mode_t m)
{
	if(S_ISREG(m))
		putchar('-');
	else if(S_ISDIR(m))
		putchar('d');
	else if(S_ISCHR(m))
		putchar('c');
	else if(S_ISBLK(m))
		putchar('b');
	else if(S_ISFIFO(m))
		putchar('p');
	else if(S_ISLNK(m))
		putchar('l');
	else if(S_ISSOCK(m))
		putchar('s');

	return;
} 
void get_filePermission(mode_t m)
{
	for(int i=0;i<9;i++)
	{
		if((m&(0400>>i))==0)
		{
			putchar('-');
			continue;
		}
		//能运行到当前位置,则代表对应位置有权限
		//需要判断是r  w  x当中的哪一个
		switch(i%3)
		{
		case 0:putchar('r');break;
		case 1:putchar('w');break;
		case 2:putchar('x');break;
		}
	}
	return;
}
int getstat(char *str)
{	struct stat buf;
	if(stat(str, &buf) < 0)
	{
		ERR_MSG("stat");
		return -1;
	}

	//文件的类型和权限
	printf("0%o ", buf.st_mode);
	get_fileType(buf.st_mode);   
	//文件的硬链接数
	printf("%ld ", buf.st_nlink);

	//文件的所属用户
	//printf("uid: %d\n", buf.st_uid);
	//将uid转换成名字
	struct passwd* pwd = getpwuid(buf.st_uid);
	if(NULL == pwd)
	{
		ERR_MSG("getpwuid");
		return -1;
	}
	printf("%s ", pwd->pw_name);


	//文件所属组用户
	//printf("gid: %d\n", buf.st_gid);
	//将gid转换成名字
	struct group* grp = getgrgid(buf.st_gid);
	if(NULL == grp)
	{
		ERR_MSG("getgrgid");
		return -1;
	}
	printf("%s ", grp->gr_name);
	//文件大小
	printf("%ld ", buf.st_size);
	//文件的修改时间
	struct tm* info=NULL;
	info=localtime(&buf.st_mtime);
	//printf("%ld ",buf.st_ctime);
	printf("%02d %02d %02d:%02d ",info->tm_mon+1,info->tm_mday,info->tm_hour,info->tm_min);
	printf("%s\n",str);
}

int main(int argc, const char *argv[])
{
	char str[20]="";
	printf("please enter a filename:");
	scanf("%s",str);

	struct stat buf;
	if(stat(str,&buf) < 0)
	{
		ERR_MSG("stat");
		return -1;
	}

	if((buf.st_mode & S_IFMT) == S_IFDIR)
	{
		DIR * dp = opendir(str);
		if(NULL == dp)
		{
			ERR_MSG("opendir");
			return -1;
		}
		printf("open success \n");

		struct dirent *rp = NULL;
		int i=0;
		while(1)
		{
			rp = readdir(dp);
			if(NULL == rp)
			{
				if(0 == errno)
				{
					printf("读取完毕\n");break;
				}
				else
				{
					perror("readdir");
					return -1;
				}
			}
			if(*(rp->d_name) != '.')
				getstat(rp->d_name);
			//	printf("[%d]%s\n",++i,rp->d_name);
		}
		closedir(dp);
	}
	else
		getstat(str);

	return 0;
}

2.文件IO函数实现,拷贝文件。子进程先拷贝后半部分,父进程再拷贝前半部分。允许使用sleep函数。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
int main(int argc, const char *argv[])
{
	int fd_r = open("./1.txt",O_RDONLY);
	if(fd_r < 0)
	{
		ERR_MSG("open");
		return -1;
	}
	int fd_w = open("./2.txt",O_WRONLY|O_CREAT|O_TRUNC,0664);
	if(fd_w < 0)
	{
		ERR_MSG("open");
		return -1;
	}
	off_t len = lseek(fd_r,0,SEEK_END);
	pid_t cpid = fork();
	if(cpid > 0)
	{
		sleep(1);
		lseek(fd_r,len/2,SEEK_SET);
		lseek(fd_w,len/2,SEEK_SET);
		char c;
		for(int i=len/2;i<len;i++)
		{
			if(read(fd_r,&c,1) == 0)
			{
				break;
			}
			write(fd_w,&c,1);
		}
	}
	if(0 == cpid)
	{
		lseek(fd_r,0,SEEK_SET);
		lseek(fd_w,0,SEEK_SET);
		char a;
		for(int j=0;j<len/2;j++)
		{
			if(read(fd_r,&a,1) == 0)
			{
				break;    
			}
			write(fd_w,&a,1);
		}
	}
	close(fd_r);
	close(fd_w);

	return 0;
}    

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值