Linux:文件描述符

我们之前就知道在Linux操作系统下 “一切皆文件” ,所以在这个条件下,所有研究的对象都变相的相当于研究文件,那么对文件系统的研究也应该是必须的。

文件描述符fd

我们的内核利用文件描述符来访问文件,每个文件描述符都是非负整数,打开现存的文件或者是新建文件时,内核会返回一个文件描述符,读写文件也需要使用文件描述符来指定待读写的文件。

这样说来,其实每个打开的文件,都对应属于其本身的一个文件描述符。

  • Linux进程默认的情况下会有三个默认打开的文件描述符。即标准输入0,标准输出1,标准错误2
  • 0 ,1,2对应的物理设备一般是键盘、显示器、显示器

    这里写图片描述

由图可以理解到,在我们进程的进程控制块即PCB中有一个结构体指针file,它指向了一个files_struct结构体,这个结构体内保存着一个指针数组,其每个元素都是一个指针,这个指针就是打开文件的指针,而我们所谓的文件描述符就是这些指针的下标,所以只要拿着文件描述符就可以找到对应的文件。

#include <stdio.h>

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

int main()
{
    int fd = open("myfile",O_RDONLY);
    if(fd < 0)
    {
        perror("open");
        return 1;
    }
    printf("fd: %d\n",fd);

    close(fd);

    return 0;
}

这里写图片描述

这个也验证了在Linux下,系统默认打开三个文件,即标准输入、标准输出、标准错误。而我们打开一个新的文件,文件描述符是从3开始的。

重定向

先看一个代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.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;
}

这里写图片描述

我们发现,当我们利用close关闭掉文件描述符1所对应的文件时,然后进行printf,竟然在运行test的时候屏幕没有输出。这是为什么呢?

我们之前说过,系统默认打开三个文件,即标准输入、标准输出、标准错误,也就是在我们关闭1之后,标准输出被关闭了,标准输出一般对应的是显示器,所以在我们printf的时候,在file_struct结构体中,file*回去寻找此时文件描述符为1的内容进行打印,它并不知道此时的1已经不是对应的显示器了,而这个时候的1则对应我们打开的新文件,即myfile,所以他将内容写入了这个文件。

这里写图片描述

常见的重定向有:> < >>其中>>为追加重定向。

FILE

  • 因为IO相关函数与系统调用接口对应,并且库函数封装系统调用,所以在本质上,访问文件都是通过fd来进行访问的
  • 所以在C库当中的FILE结构体内部,必定封装了fd
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
    const char* msg0 = "hello prntf\n";
    const char* msg1 = "hello fwrite\n";
    const char* msg2 = "hello write\n";

    printf("%s",msg0);
    fwrite(msg1,strlen(msg1),1,stdout);
    write(1,msg2,strlen(msg2));


    fork();

    return 0;
}

这里写图片描述

我们发现在直接运行./test的时候,显示器打印三行hello,而我们队进程实现重定向的时候,发现printf与fwrite打印了两次,而write只有一次。这是为什么?

C库函数写入文件的时候是进行的全缓冲,而写在显示器上是行缓冲,所以我们在定义时定义成全部都是\n结尾,也就是说在屏幕上输出的时候,直接输出整句话,不再等待。所以显示了三句话。而当我们由屏幕改为文件后,原来的行缓冲输出被变成了全缓冲,此时\n只是单纯的换行,并不会直接输出,那么这个时候由于fork()函数的存在子进程也拥有一份父进程相同的数据,那么最终重定向到文件的时候,则将缓冲区内的所有内容全部定向到新的文件当中,所以也就出现了五句话,那么为什么write这句话并没有在文件当中呢?原因是因为printf,fwrite都为库函数,而库函数自带缓冲区,而write为系统调用,它没有缓冲区,也就是说他直接输出。

库函数其实是在系统调用的基础上对系统调用进行封装,但是write并未有缓冲区,而fwrite有缓冲区是为什么呢?这其实是因为这个缓冲区是二次加上的,有C标准库提供。


欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值