fd与FILE以及fork缓冲问题

一、文件描述符(fd)

1.文件描述符其实就是一个非负的小整数。是文件指针数组的下标。
2.让我们看一看0,1,2,…代表什么?

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>

int main()
{
    char buf[1024];
    printf("fd0\n");
    ssize_t s=read(0,buf,sizeof(buf));
    if(s>0)
    {
        buf[s]=0;
        printf("fd1\n");
        write(1,buf,strlen(buf));
        printf("fd2\n");
        write(2,buf,strlen(buf));
        printf("fd3\n");
        write(3,buf,strlen(buf));
    }
    return 0;
}

这里写图片描述
从运行程序来看,文件描述符0,1,2是Linux默认情况下三个缺省打开的。3不是缺省的。
0,1,2对应的物理设备分别是键盘、显示器、显示器。

//标准输入、输出
执行一个shell命令行时通常会自动打开三个标准文件,
即标准输入文件(stdin),通常对应终端的键盘;
标准输出文件(stdout)和标准错误输出文件(stderr),这两个文件都对应终端的屏幕。

3.文件描述符如何做到找到对应文件的?
这里写图片描述
每个进程都有一个PCB,每一个PCB中都包含一个file指针,它指向一个文件结构体,结构体中包含了一个文件指针数组,每个元素都包含了一个指向打开文件的指针!,所以文件描述符就是该文件指针数组的下标,因此,我们只需要知道文件描述符,就可以通过文件描述符去找到指针指向的文件。

4.文件描述符的分配规则

在file_struct结构体中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。
//文件描述符也是一种资源,这种分配规则可以很好的利用资源。

1)当没有关闭默认文件描述符时,新文件的文件描述符等于3。
2)当关闭了0时,新文件的文件描述符是0。
3)关闭使用close(0)

5.重定向
概念:将各种请求重新定个方向转到其它位置
分类:重定向有输出重定向(>)、输入重定向(<)、追加重定向(>>)。
⑴先看一个小程序,关闭文件描述符1,分配给新文件

#include <stdio.h>
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <stdlib.h>
int main()
{
    close(1);
    int fd = open("myfile", O_WRONLY|O_CREAT, 00644); 
    if(fd < 0){
        perror("open");     
        return 1;
    }
    printf("fd: %d\n", fd); 
    fflush(stdout);
    close(fd);
    return 0;
}

⑵根据分配规则,新打开的文件接收到的文件描述符是1,但结果是什么呢?看下图↓
这里写图片描述
我们发现,fd:1本来是往屏幕输出的,可是它并没有,而是输出到了打开的文件中,我们把这种现象称为输出重定向。
重定向有输出重定向(>)、输入重定向(<)、追加重定向(>>)。
那它到底发生了什么?看下图↓
这里写图片描述
⑶printf是C库函数,本应该往stdout中输出,但此时fd:1的下标存放的是新文件的地址。也就是说标准输出被占用了,无法往显示器输出,这叫输出重定向。

二、FILE

1.FILE是在stdio.h定义的保存文件流信息的一个结构体类型
2.本质上访问文件都是通过fd访问的,库函数封装了fd,所以,FILE结构体内部肯定封装了fd。
3.fork缓冲问题。

//行缓冲:比如写入显示器中,输入的数先进入行缓冲区,当满足条件时,在进一步输出到屏幕。
//全缓冲;比如写入文件中。
//无缓冲

①使用三种操作方式(库函数、系统调用)往显示器打印数据

int main()
{
    const char *msg0="printf\n"; 
    const char *msg1="fwrite\n"; 
    const char *msg2="write\n";
    printf("%s", msg0);
    fwrite(msg1, strlen(msg0), 1, stdout); 
    write(1, msg2, strlen(msg2));
    fork();
    return 0;
}

这里写图片描述
②对进程进行输出重定向
这里写图片描述
为什么会出现这种现象呢?不应该都是出现两次吗?
答:当进程输出重定向到新文件时时,数据的缓冲方式由行缓冲转换为全缓冲,printf与fwrite(库函数自带缓冲区)先进入了全缓冲区,不会立即被刷新;write是系统调用,没有缓冲区,直接输出到了屏幕,当下一步执行fork()函数时,子进程的执行起点为fork之后,但此时父子数据会发生写时拷贝,所以当父进程全缓冲区准备刷新的时候,子进程也有了同样的一份数据,随机产生两份数据。那为什么子没有write数据呢?因为写时拷贝,只有在写入时,数据才被复制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值