【Linux IO】文件描述符、重定向、缓冲区

1.open函数

【Linux IO】文件描述符、重定向、缓冲区_第1张图片

1.1第二个参数的解释;

O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
         上面三个常量,必须指定一个且只能指定一个
O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND: 追加写
【Linux IO】文件描述符、重定向、缓冲区_第2张图片
open("test.txt",O_WRONLY|O_CREAT,0644/*八进制给初始值*/);
【Linux IO】文件描述符、重定向、缓冲区_第3张图片

1.2open的返回值(重点)

  • 返回值是struct file*指针数组的下标

  • 0:标准输入1:标准输出2:标准错误

#include
#include
#include
#include
#include
using namespace std;

int main()
{
    int fd1=open("test.txt",O_WRONLY|O_CREAT,0644/*°???????*/);
    int fd2=open("test.txt1",O_WRONLY|O_CREAT,0644/*°???????*/);
    int fd3=open("test.txt2",O_WRONLY|O_CREAT,0644/*°???????*/);
    int fd4=open("test.txt3",O_WRONLY|O_CREAT,0644/*°???????*/);
    printf("%d %d %d %d\n",fd1,fd2,fd3,fd4);
    return 0;
}

执行结果:

原理:

【Linux IO】文件描述符、重定向、缓冲区_第4张图片

2.文件描述符fd

2.1文件描述符的分配规则

上面说了,进程PCB中有一个指向files_struct的指针,这个结构体中又包含一个struct file的指针数组,打开文件就会在指针数组依次添加

那么关闭默认打开的标准输入、标准输出、标准错误文件,会发生什么结果呢?

关闭标准输入,那么新打开文件的文件描述符就是0了

#include
#include
#include
#include
#include
using namespace std;

int main()
{
    close(0);
    int fd1=open("test.txt",O_WRONLY|O_CREAT,0644);
    if(fd1<0)
    {
        cerr<<"open fail";
        return 1;
    }
    cout<<"fd1:"<

有上述可以得出文件描述符的分配规则:在files_struct指针数组当中,找到当前没有被使用的 最小的一个下标,作为新的文件描述符。

2.2输入输出重定向

把标准输出关闭在打开一个新文件,再打印就会发现不会打印在显示器,创建的文件中有我们打印的内容,出现了一个输出重定向

#include
#include
#include
#include
#include
#include
using namespace std;

int main()
{
    close(1);
    int fd1=open("test.txt",O_WRONLY|O_CREAT,0644);
    if(fd1<0)
    {
        cerr<<"open fail";
        return 1;
    }
    cout<<"fd1:"<

输出重定向原理:

【Linux IO】文件描述符、重定向、缓冲区_第5张图片

追加重定向只是在打开文件时加一个O_APPEND

#include
#include
#include
#include
#include
#include
using namespace std;

int main()
{
    close(1);
    int fd1=open("test.txt",O_WRONLY|O_CREAT|O_APPEND/*这里修改了*/,0644);
    if(fd1<0)
    {
        cerr<<"open fail";
        return 1;
    }
    cout<<"fd1:"<

我前面执行了几次

【Linux IO】文件描述符、重定向、缓冲区_第6张图片

输入重定向

#include
#include
#include
#include
#include
#include
using namespace std;
int main()
{
    close(0);
    int fd=open("./test.txt",O_RDONLY);
    if(fd<0)
    {
        cerr<<"open fail";
        return(1);
    }
    char s[50];
    while(fgets(s,sizeof(s)-1,stdin))
        cout<

2.3dup2

需要重定向是就关闭文件是不是有些麻烦了,使用dup2函数也可以做到一样的效果;

原理:将oldfd拷贝newfd(标准输入、标准输出、标准错误)

【Linux IO】文件描述符、重定向、缓冲区_第7张图片
#include
#include
using namespace std;
int main()
{
    int fd=open("test.txt",O_WRONLY|O_TRUNC|O_CREAT);
    if(fd<0)
    {
        cerr<<"opne fail";
        return 1;
    }
    dup2(fd,1);
    cout<<"hello wrold"<

2.4提出一些问题

Q:如果程序替换文件描述符会改变吗?

A:不会,因为指向文件结构体的指针保存在PCB中的指向的files_struct结构体中的指针数组内,文件描述符是这个指针数组的下标,程序替换替换的是代码和数据;

Q:创建子进程,子进程文件描述符会怎么初始化和文件会新增吗?

A:子进程的PCB是使用父进程的PCB来初始化的,子进程创建PCB,文件描述符使用父进程初始化所以相同,文件当然不会新增,文件在磁盘中只有一份;

3.缓冲区

  • write把数据拷贝到内核缓冲区;

  • printf库函数把数据拷贝到C语言缓冲区,按刷新策略刷新到内核缓冲区

进程退出时,会将FILE内部的数据刷新到系统缓冲区,再调用系统接口,用户->OS

三种刷新策略:

1.不缓存(直接刷新)

2.行缓冲\n,endl,例:输出到显示器

3.全缓冲(把缓冲区填满就刷新到内核缓冲区),例:写入磁盘文件

【Linux IO】文件描述符、重定向、缓冲区_第8张图片
#include
#include
#include
using namespace std;
int main()
{
    const char* s1="hello buffer\n";
    write(1,s1,strlen(s1));
    printf("hello world\n");
    fprintf(stdout,"hello world\n");

    close(1);
    return 0;
}

执行结果:原本打印显示器重定向写到磁盘文件,C语言缓冲区刷新策略由行刷新变为了全刷新,在函数结束前关闭了磁盘文件,保存在1号FILE的字符串生命周期结束,那么就没有时间刷新C语言缓冲区到OS缓冲区

【Linux IO】文件描述符、重定向、缓冲区_第9张图片

3.1缓冲区属于PCB、代码、数据哪一个?

#include
#include
#include
using namespace std;
int main()
{
    const char* s1="hello buffer\n";
    write(1,s1,strlen(s1));
    printf("hello world\n");
    fprintf(stdout,"hello world\n");
    fork();
    return 0;
}

执行结果:C语言缓冲区的数据属于数据,所以遵守写实拷贝的规则,父子进程谁先刷新指向C语言的指针减1,为0就释放

【Linux IO】文件描述符、重定向、缓冲区_第10张图片

你可能感兴趣的:(Linux,c++,算法,开发语言)