文件与文件描述符
复习
- 内存分配与碎片:操作系统怎样切分、回收和整理内存
- 设备控制器与驱动程序:用统一接口隐藏硬件差异
- 查询、中断与 DMA:CPU 参与设备传输的程度怎样逐步降低
TL;DR
- 文件把设备和持久数据,统一成可读写的“字节流”
- 文件有名字,能打开、读、写、关闭
- 打开文件后拿到的凭据叫文件描述符
- 之后所有读写,都通过这个描述符进行
正文
设备能读写了,可接下来还有个问题:程序要保存一份数据,怎样操作才方便?
文件:统一的字节流
如果让程序直接和硬盘打交道,它得知道数据放在哪个扇区、怎么组织、怎么找——太麻烦。于是操作系统给出一个抽象:文件(file)。
文件把“磁盘上某个位置的若干数据”,包装成一个有名字、能顺序读写的对象。程序眼里,文件就是一条字节流:从头到尾一堆字节,可以打开、读若干、写若干、关上。至于这些字节究竟落在磁盘的哪里,文件系统替我们操心。
顺带一提,在“一切皆文件”的设计里,设备也被当成文件:键盘是“你只能读的文件”,屏幕是“你只能写的文件”。于是 read、write 这套接口,同时服务于磁盘文件和设备——又一层统一。
打开与描述符
要用一个文件,先得打开它。打开之后,内核返回一个文件描述符(file descriptor)——通常就是个小小的整数编号:
打开 "data.txt" → 返回描述符 3
read(3, ...) // 读
write(3, ...) // 写
close(3) // 关
这个编号,是内核给你的一张“凭据”。之后你对这个文件的所有操作,都靠它来指明“是哪一个”。
可以把它想成去图书馆借书:书是文件,借阅证上的一串编号就是描述符。你不必记住书在哪个书架的哪个位置,只要出示编号,管理员就去替你取、替你放。
为什么要绕这一道
为什么不直接拿文件名操作,而要“先打开、拿编号”?
- 省去反复查找:打开时查一次位置,之后用编号直达,不必每次都按名字找
- 记录状态:读到哪了、用了什么模式,都记在这份“打开”里
- 便于管理:内核用编号统一管理所有打开的文件,用完能可靠地收回
于是,文件、描述符、读写接口,就构成了程序访问持久数据的基本方式。可文件一多,名字该怎么办?下一章,我们看目录与路径。
思考题
“一切皆文件”是个很流行的设计。把设备也当成文件,好处是什么?什么类型的设备,可能不太适合用“文件”来抽象?
小结
知识点
- 文件:有名字、可读写的字节流
- 文件描述符:打开文件后拿到的凭据
- read / write / close 通过描述符操作
- 设备也可被抽象为文件
参考资料
- Wikipedia(zh):文件:文件
- Wikipedia(zh):文件描述符:file descriptor
思考题答案(仅供参考)
好处是接口统一:无论是磁盘文件、键盘、屏幕还是管道,程序都能用同一套“打开、读、写、关”来操作,学习成本低、代码复用高。但有些设备并不天然适合“文件”:比如需要精确时序控制的设备、面向“消息”而非“字节流”的设备,或者状态复杂、不适合顺序读写的外设。对这些,硬套“文件”可能别扭,往往还得配合额外的专用接口。可见抽象很有用,但也不是万能的。
协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
封面图
设计师 | 南国微雪