厦门网站建设 首选猴子网络,出口商出口外贸流程,管理手机网站首页,视频网站开发方法【基础IO⑧】#xff1a;进程与文件之间的联系(文件描述符fd#xff09; 一.前言探讨[进程与文件关系]二.C语言文件操作三.系统文件调用1.open/write 四.文件描述符fd 一.前言探讨[进程与文件关系]
我们首先了解一些基本的认识#xff1a; 1.文件包括文件内容和文件属性 2.… 【基础IO⑧】进程与文件之间的联系(文件描述符fd 一.前言探讨[进程与文件关系]二.C语言文件操作三.系统文件调用1.open/write 四.文件描述符fd 一.前言探讨[进程与文件关系]
我们首先了解一些基本的认识 1.文件包括文件内容和文件属性 2.文件分为打开文件和没有打开文件。 3.打开的文件是谁打开的呢又是如何打开的呢这是我们本篇的重点处理问题。 4.没有打开的文件在哪里放着呢 对于打开的文件我们重点想了解是谁打开的并且是如何打开的。对于没有打开的文件我们重点想了解这些没有被打开的文件在哪里 1.打开的文件的操作肯定是我们写代码才能操作所以也就是我们的程序即进程是进程打开文件。 2.对于没有打开的文件肯定很多那这些文件是如何被分门别类的放置好的呢这是我们要探讨的问题因为我们想对这些未打开的文件快速的进行增删查改。 进程打开了文件本质上就是要研究进程和文件之间的关系。 要想访问一个文件首先需要将文件加载到内存里并且一个进程可以打开多个文件所以操作系统内部肯定存在很多被打开的文件那么这些被打开的文件操作系统也需要对他们进行管理。通过先描述再组织的方式进行管理----每一个被打开的文件操作系统都会给它创建一个文件对象这个对象包含文件的很多属性。 所以综上我们要想探讨一个被打开的文件本质上是探讨进程与文件之间的关系即-------进程PCB与文件对象之间的关系。 二.C语言文件操作
C语言的常见文件操作就是fopen fwritefread fclose等打开文件写入文件输出文件等操作。 对于fopen(参数1参数2)的使用很简单就是打开某个路径下的文件以什么样的方式打开. 所以如果不指定文件在哪个路径下系统会默认将当前进程的路径添加上去也就是在当前进程目录下创建。 所以如果我们将进程的当前目录修改就可以将文件新建到别的地方了。 1.‘w’就是以写的方式打开。不过要注意w在写入之前都会对文件进行清空操作。比如像重定向里的打开文件但不往里面写就会直接清空文件说明重定向操作里面打开文件的方式就是w。 2.‘a’也是写入操作只不过在打开文件时不会清空文件而是直接追加在内容末尾。 3.这里还有一个问题就是当使用fwrite时后面计算字符串的大小需不需要1因为\0的原因就很困扰为什么有时加1有时不加1呢 首先我们要明白字符串是C语言规定出来的它的后面必须要有\0。但文件就不认识C语言文件只需字符的内容就可以了所以当我们往文件里写入时字符串时都不需要加1直接计算字符串的长度即可。 还有一个知识那就是C语言下会默认给我们打开3个标准输入输出流
三.系统文件调用
文件其实是在磁盘上的磁盘又是属于硬件设备。操作系统的构成用户层在最上面硬件在最下面用户要想访问硬件必须要通过操作系统而操作系统又因为安全性只会给你提供系统调用接口来访问。 所以所有的库函数只要要访问硬件资源就一定要封装系统调用接口。
1.open/write 有两个open接口这两个的区别在于第三个参数有和没有。 对于已经存在的文件肯定有它自己的权限设置这样才可以被访问所以当一个文件被创建时必须要设置这个文件的权限属性。 而第三个参数就是用来设置权限的。所以第一个open是用来打开已经存在的文件而第二个open是用来打开创建一个没有存在的文件的并设置这个文件的权限。我们主要用三个参数的open调用接口。 open系统调用接口的参数第一个就是文件路径第二个参数是打开的方式第三个参数是用过给这个文件设计权限的。返回值是int类型 open是系统调用接口它有自己的打开文件的方式它是采用比特位方式的标志位传递参数从而采用不同的打开方式。 O_WRONLY表示只写形式 O_CREAT表示如果文件不存在就创建 O_TRYNC表示打开文件之前先清空文件 O_APPEND表示追加不清空。 所以C库函数fopen里封装着open系统调用函数w方式就是O_WRONLY, O_CREAT, O_TRYNC三种方式组合a方式就是 O_WRONLY, O_CREAT, O_APPEND三种方式组合。
fopen封装着open这个我们应该能理解不过你没有注意到open的返回值是int类型而fopen的返回值确实FILE类型int类型和FILE类型之间有什么关系呢
四.文件描述符fd
我们知道只要打开一个文件操作系统就要给这个打开的文件创建个文件对象struct file。这个对象描述着文件许多属性。文件对象之间用链表连起来。这样操作系统对于文件的管理就转换为对链表的增删查改了。
我们前面也说过一个进程可以打开多个文件所以操作系统内部肯定有许多被打开的文件那么进程是怎么知道它打开的是哪个文件呢 其实进程PCB里存在一个指针对象叫做struct file_struct对象。 它指向的是一个结构体对象这个结构体里面存着一个数组struct file arr[]这个数组叫做文件描述符表里面存的都是文件对象的地址。当进程要打开一个文件是操作系统首先会为这个文件创建struct file对象。然后就会将这个对象地址存放在文件描述符表里。当又打开一个文件就依次将文件对象的地址放进数组里面最后返回该数组的下标给进程。最后调用open打开创建一个文件后就会获得一个int类型的下标。所以本质上这个int类型的返回值就是数组的下标。也就是文件描述表的下标。而进程就是通过这个下标再次找到被打开的文件的。 所以这个下标也叫做文件描述符。本质上就是文件对象在文件描述表里位置。 所以进程是通过文件描述符fd来找到被打开的文件的。这也是为什么open返回值为什么是int类型了。 因为进程可以打开多个文件所以这里采用的引用计数的方式进行关闭每个文件对象都有一个计数器当进程close这个文件时计数器就减减减完后如果计数器不为0则说明还有其他进程在使用这个文件则不真正关闭文件当计数器为0时才真正的关闭文件。
open返回的是文件描述符fd。但fopen返回的确实FILE类型这是怎么回事呢 其实在操作系统它只认识文件描述符fd并不认识FILE。进程与文件之间本质是通过数组下标来联系的。 所以不管FILE是什么它内部肯定封装着文件描述符fd。FILE其实一个结构体对象。后面我会详细介绍它。
所以对于文件操作来说进行了两次封装一次是函数层面的封装库函数封装系统调用一次是类型方面封装FILE类型里面封装fd类型。
到这里我们就可以验证一个现象了 你说C语言默认给我们打开了三个标准输入输出流你怎么证明呢 文件既然被打开了操作系统就会给它创建结构体对象struct file。并且会将它的地址放入文件描述符表里一开始文件描述符表里一个都没有现在这三个放进去应该分别对应的数组下标是 0 1 2.所以我们可以观察他们的文件描述符是什么。