文件fd【Linux系统编程】

本文详细解释了基础IO中的文件fd操作,包括打开文件的原理、C语言中的fopen接口、系统调用接口(如open和write)以及文件描述符的管理。还涉及了重定向和缓冲区的概念,以及它们在编程实践中的应用。
摘要由CSDN通过智能技术生成

本文是基础IO的第一个部分,基础IO部分将主要讲解以下内容:文件fd 文件系统 软硬链接 操作系统的内存管理 以及 动静态库。本节重点讲解文件fd,其余内容将在后面的博客更新。

一、共识

文件 = 内容 + 属性

文件分为打开了的文件和没打开的文件。

打开的文件:谁打开?进程 (本质是研究进程和文件的关系)

没打开的文件:磁盘里,很多,如何存储?------>快速增删查改。

本节重点讨论打开的文件!

文件被打开,必须先加载到内存,且是其属性先加载到内存,一个进程可以打开多个文件。

操作系统内,一定存在着大量被打开的文件,要对他们进行管理:先描述,再组织!

此时对文件的管理,就转换成对链表的增删查改。

目录

一、共识

二、C文件接口

三、过渡到系统,认识文件系统调用

四、访问文件的本质

五、重定向和缓冲区

重定向

缓冲区 


二、C文件接口

FILE *fp = fopen ("log.txt","w");

如果没有指定路径,默认在当前路径创建(当前路径指进程的当前路径,即cwd,如果更改了cwd,就把文件创建到新的路径了)。

child("/home/JY");//更改当前进程的工作路径。

size_t fwrite ( const void *ptr,size_t size,size_t nmemb,FILE * stream );

size:一个基本单位的大小

nmemb:几个基本单位

const char *message = "hello Linux";
fwrite(message,strlen(message),1,fp);

"w" 写入前,会先对文件进程清空。

(echo "hello Linux" > log.txt 输出重定向本质:打开log.txt 文件,清空,再写入)。

"a" 追加,往文件结尾处写。

三、过渡到系统,认识文件系统调用

文件在磁盘上,访问文件,就是访问硬件。用户不能直接访问硬件,必须通过系统调用接口。

打开文件的系统调用接口:

int open ( const char *pathname,int flags,mode_t mode)

pathname:文件路径

mode:文件权限,如果没传,文件的权限可能为乱码,手动传了之后,注意还有umask(更改当前进程的umask:umask(0));

flags:打开文件的方式(比特位级别的传参方式)

        可传:O_RDONLY(只读) O_WRONLY(只写) O_RDWR(读写)

        O_CREAT(创建) O_APPEND(追加)O_TRUNC (清空)等等。

头文件:<sys/types.h> <sys/stat.h> <fcntl.h>

补充:比特位级别的传参

C语言里的fopen函数就是对open系统调用接口的封装!

如:FILE *fp = fopen("log.txt","w");

其内部一定封装了:int fd = open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);

以“w”方式打开,如果文件不存在,会自动创建一个,所以要带O_CREAT;打开文件后,会先清空文件内容,所以要带O_TRUNC。

ssize_t write ( int fd,const void * buf,size_t count );

ssize_read ( int fd,void * buf,size_t count );

四、访问文件的本质

open的返回值fd本质就是array数组的下标,FILE是C库自己定义的struct,其中必定也封装了fd。 printf("stdin->fd:%d\n",stdin->fileno);

 补充:系统默认打开3个文件,键盘文件、显示器文件、显示器文件

在C语言里就是stdin,stdout,stderr

关闭文件:struct file里有一个引用计数count,在调用close(1), 会将1号文件的count--;判断count是否为0,在将struct file* 置空,为0就回收该struct file。

五、重定向和缓冲区

文件描述符的分配规则是什么?

从0小标开始,寻找最小的没有使用的数组位置,它的下标就是新文件的文件描述符。

重定向

close(1)之后,1号位置指向空,open log.txt时,从小下标开始找,找到1,就让1指向log.txt,所以后面在向1号文件write时,就是往log.txt里写入了。这就是重定向的原理。

其实不用先关闭再打开,只需要有一个系统接口能将3号指针拷贝给1号指针,就能完成重定向。 

对应的系统调用接口:

追加重定向:把选项O_TRUNC改为O_APPEND

缓冲区 

C缓冲区刷新:

a、无缓冲(直接刷新)        b、行缓冲        c、全缓冲(文件)

先看一个现象,下面程序运行时,为什么没有结果输出到显示器?

每个打开的文件都有一个语言级别的缓冲区,C语言里的printf/fprintf/fwrite等,会先将数据写到C语言提供的缓冲区里(区别于内核级缓冲区),它会在某些时机刷新到内核级的缓冲区。在本例中,fwrite写到了C语言级的缓冲区,然后就将1号显示器文件关闭了,并没有写入内核级的缓冲区,因此,没有成功将数据写入1号显示器文件。 

现象二:上面的代码是能成功打印hello Linux的。

write是系统接口,会直接将数据写入内核级缓冲区,所以即使没有‘\n’,也会显示结果。

现象三:

由显示器重定向到文件时,刷新方案由行缓冲变成了全缓冲,write是直接写到系统缓冲区的,而printf等C接口本来是行缓冲,但变为了全缓冲,就先不刷新了,fork创建子进程后,发生写时拷贝,因此数据多了一份,进程结束后,就刷新了缓冲区。

 用户刷新的本质:将数据通过write写到内核中,平时用的flush一定封装了write。

进程退出时,也会刷新缓冲区,那为什么还需要语言级的缓冲区呢?

1、解决效率问题

2、配合格式化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值