文件流指针和文件描述符

1.文件流指针和文件描述符的产生

fopen函数打开文件成功后会返回文件流指针,open函数打开文件成功后返回的是文件描述符.他俩的相同点是通过文件流指针和文件描述符都可以对文件进行操作.

2.fopen函数和open函数的介绍

fopen函数(库函数)

path:带有的路径的文件名,如果没有路径默认在当前文件下.

mode:

'r' 只读方式打开,将文件指针指向文件头,如果文件不存在,则返回空。
'r+' 读写方式打开,将文件指针指向文件头,如果文件不存在,则返回空。
'w' 写入方式打开,将文件指针指向文件头并将文件内容清空。如果文件不存在则创建。
'w+' 读写方式打开,将文件指针指向文件头并将文件内容清空。如果文件不存在则创建。
'a' 写入方式打开,将文件指针指向文件末尾。如果文件不存在则创建。
'a+' 读写方式打开,将文件指针指向文件末尾。如果文件不存在则创建。
例如:FILE* fp = fopen("1.txt", "w+");

open函数(系统调用函数)

pathname:带有的路径的文件名,如果没有路径默认在当前文件下.

flags:打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“运算,构成flags

参数 :
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
        这三个常量,必须指定一个且只能指定一个
O_CREAT : 若文件不存在,则创建它。需要使用 mode 选项,来指明新文件的访问权限
O_APPEND: 追加写
返回值: 成功:新打开的文件描述符,失败返回-1
例如:int p=open("1.txt", O_RDONLY|O_CREAT,0664);两个宏之间用 位图运算,0664是打开的文件的权限

3.文件描述符的介绍和怎么查看文件描述符

文件描述符是打开文件后返回的值,通过文件描述符可以操作文件,而每一个进程在运行时都会默认打开标准输入,标准输出,表述错误.这三个文件描述符.

打开一个文件然后进入死循环

int p=open("11.txt",O_RDWR | O_CREAT,0664);
    if(p<0)
    {
        return 0;
    }
    while(1)
    {

    }

用pa aux | grep mytext查看进程号

ll .proc/进程号/fd     查看进程打开的文件描述符.

 

 0:标准输入

1:标准输出

2:标准错误

3:程序里打开的文件的文件描述符

文件描述符就相当于文件的标记:标记的规则是最小数规则

在打开文件之前关闭标准输入文件,

 

 0代表的文件被关闭,所以打开文件后1.txt文件的文件描述符就是0;

4.从内核角度理解文件流指针和文件描述符

文件描述符:

每一个进程在内核里都是一个struct task_struct结构体:

结构体里看到了我们熟悉的pid

这是一个struct files_struct指针(描述的是当前进程打开文件的信息)

这个结构体指针指向的struct files_struct类型的变量,变量里里有一个struct file_rcu*fd_array[NR_OPEN_DEFAULT],这个结构体指针数组里的数组下表就是文件描述符,数组当中的元素是指针类型,指向了文件,所以通过文件描述符,就可以找到对应的文件.

图文关系如下:

文件流指针:

FILE可以在stdio.h的头文件里使用说明这个指针在这个文件里存在.直接cd /usr/include

打开包含头文件的文件夹,vim stdio.h.就能看到这个头文件里有啥了...(.h文件里基本上都是声明)

 

 第一个struct _IO_FILE是一个结构体的声明;

第二个是FILE指针是被重命名出来的,他的本来面目是struct _IO_FILE这个结构体

找到struct _IO_FILE结构体的办法:

在include文件下面进行搜索,grep struct _IO_FILE . -R(意思是在当前文件下进行递归搜索)

 打开结构体定义对应的文件libio.h,找到结构体的定义:

 char* _IO_read_ptr;   /* Current read pointer */     表示当前读到了哪个位置
 char* _IO_read_end;   /* End of get area. */   表示当前读区域的末尾
char* _IO_read_base;  /* Start of putback+get area. */  表示读区域的起始位置
char* _IO_write_base; /* Start of put area. */      写缓冲区的起始位置
char* _IO_write_ptr;  /* Current put pointer. */       写到了哪个位置
char* _IO_write_end;  /* End of put area. */          写缓冲区的末尾位置

文件描述符里包含这些指针,在文件进行读写的时候告诉函数应该从哪读;

int _fileno;  保存文件描述符的数值,

代码验证

#include<stdio.h>

int main()
{
    FILE*fp=fopen("1.text","w");
    printf("%d\n",fp->_fileno);
}

结果是

标准输入标准输出和标准错误分别是0,1,2,根据最小值规则,文件的文件标识符就是3

 图文匹配

struct _IO_FILE{...}这个结构体是标准库当中的结构体,该结构体里上述的指针维护的缓冲区是标准库的缓冲区

5.文件描述符和文件流指针的关联

上述说到文件描述符是PCB里的一个数组的的下标,所以一个PCB里可以有多个文件描述符.等同于,PCB里包含进程打开的所有文件...而文件流指针的范围就比较小了,一个文件流指针只能保存一个文件的文件描述符,就是文件流指针只能代表一个文件.所以一个进程至少要打开三个文件,标准输入,标准输出,标准错误.

图文对比

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值