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

1.open函数

1.1第二个参数的解释;


O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
         上面三个常量,必须指定一个且只能指定一个
O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND: 追加写

open("test.txt",O_WRONLY|O_CREAT,0644/*八进制给初始值*/);

1.2open的返回值(重点)

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

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


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

执行结果:

原理:struct file 结构体内一定有:一个指向文件内容的指针(结构体就能找到文件内容)

2.文件描述符fd

2.1文件描述符的分配规则

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

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

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


#include<iostream>
#include<sys/types.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
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:"<<fd1<<endl;
    return 0;
}

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

2.2输入输出重定向

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


#include<iostream>
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
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:"<<fd1<<endl;
    return 0;
}

输出重定向原理:

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


#include<iostream>
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
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:"<<fd1<<endl;
    return 0;
}

我前面执行了几次,有多个fd1:1

输入重定向:从键盘读重定向到从文件读


#include<iostream>
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
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<<s;
    return 0;
}

2.3dup2

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

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


#include<iostream>
#include<unistd.h>
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"<<endl;
    cout<<"hello IO"<<endl;
    return 0;
}

2.4提出一些问题

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

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

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

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

3.缓冲区

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

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

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

三种刷新策略:

1.不缓存(直接刷新)

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

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


#include<stdio.h>
#include<iostream>
#include<unistd.h>
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缓冲区

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


#include<stdio.h>
#include<iostream>
#include<unistd.h>
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就释放

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值