null第六章 文件系统第六章 文件系统訾小超本章主要内容:*本章主要内容:文件系统概述
文件存储和磁盘管理的基本知识
文件目录
文件存储资源分配与管理
UNIX的文件存储和管理
文件系统相关的操作
文件系统对上层的接口:系统调用
文件相关的
I/O库函数:标准子例程
管道文件和管道通信
Linux文件系统简介1、基本概念*1、基本概念1-1 文件系统出现的背景
在程序结束后,可能会产生一些运行结果数据,这些数据并不会随程序结束而结束,需要存储在永久性的磁介质上。
早期数据管理的特点:
用户自行管理辅助存储器上的信息
按照物理地址安排信息,组织数据的输入输出 null*早期数据管理的不足:
繁琐复杂、易于出错、可靠性差。
数据共享难以实现。
磁介质难以共享。
如果共享磁介质,难以有效实现文件和其它用户(非文件主人)的隔离
存储介质的技术发展
卡片:小容量
磁带:大容量、顺序存取
磁盘:大容量、随机存取null*随着应用需求和技术发展,数据管理逐渐由个人向系统级发展:
在操作系统级出现了专门管理数据的实用工具。
最后这些实用工具集成到操作系统的内部,以系统调用的形式向应用程序提供数据管理服务。
这就形成了文件系统的雏形。null*1-2 文件系统的目标和要求
目标:方便用户管理自己的数据资源
基本要求:
文件按名存储
文件有序组织,文件名分层次管理
如支持树形目录结构
操作简单,存取效率高。
其它要求:
支持多用户系统,多用户能够共享同一个磁介质。
有一定的安全性保证,最好能进行数据恢复。
存储空间的利用率高null*1-3 文件系统的概念
文件:
由文件名字标识的一组相关信息的集合。文件名是字母或数字组成的字母数字串
文件系统:
软件观点:操作系统中,为用户和应用程序管理文件的系统软件集合。
存储格式观点:文件系统是文件在存储介质上保存和管理相关的约定。在操作系统中,这种约定的实现也被称为文件系统。一种相关约定就对应一种文件系统,所以目前存在多种文件系统:MSDOS,FAT32,NTFS,EXT2等。null*操作系统和文件系统
早期:一个操作系统一般都支持一种文件系统。在设计操作系统时,常常会专门为此设计一种文件系统。如MSDOS,Windows95,Windows98,WindowsNT,Unix,Linux等
目前:为实现文件和文件系统共享,一个操作系统除支持为它设计的文件系统外,还可能支持其他文件系统。如Linux支持Ext2,FAT等。
null*1-4、引入文件系统的好处
方便用户使用,
用户不必了解信息存储的方法、位置以及存储设备实际运作方式等细节
只要知道文件名,可存取信息,实现了“按名存取”
安全可靠性
用户通过文件系统才能实现对文件的访问,故可防止对文件信息无意的破坏。
而文件系统能提供各种安全、保密和保护
。
方便数据共享
移动存储设备。
各种形式的文件链接,不同的用户可以使用同名或异名的同一文件 null*1-5、文件的命名
文件名是字母或数字组成的字母数字串,在一些文件系统中还可能包含其它字符,如下划线等。
各种文件系统的文件命名规则略有不同,即文件名的格式和长度因系统而异。
MSDOS文件系统,一个文件的名字包括文件名和扩展名两部分;前者长度为1到8个字符;后者长度为0到3个字符;中间用一个圆点隔开
NTFS:支持多达255个字符的文件 ,而且区分大小写null*1-6、文件的类型(5大文件类型)
普通文件:即前面所讨论的存储在外存设备上的数据文件。
目录文件?
管道文件?
块设备文件:在unxi/Linux等操作系统中,对应于磁盘、光盘或磁带等块设备的文件。
字符设备文件:在unxi/Linux等操作系统中,对应于终端、打印机等字符设备的文件。null*1-7、文件的属性(*)
文件的类型属性:如普通文件、目录文件、系统文件、隐式文件、设备文件等。
文件的保护属性:如可读、可写、可执行、可创建、可删除等。
创建者属性:
创建和访问时间属性:
文件大小:
注:文件的属性随具体的需求和文件系统有关系null*1-8、数据的逻辑层次结构
字段:
最基本的语义单位。
:
多个字段的集合
文件
相同格式记录的集合
null*1-9、文件的逻辑组织方式 (记录)
堆文件
数据按到达的时间顺序收集起来,每一个记录包含了一堆集中到达的数据。
无规则的记录结构:每个记录中字段(数量或次序)可能不同,字段需要有自描述性:字段名和字段值。
数据检索复杂
一般用于:数据收集时,暂存数据。null*顺序存取:
按记录顺序进行读/写操作的存取方法称顺序存取
记录格式固定:字段个数、字段长度、字段次数都是固定的,每个记录都是相同的。
只需存储字段的值,字段名和字段长度由文件结构属性确定。
使用特点
一般用于顺序处理或批处理
对记录查询或记录更新,效率比较低
在以磁带作为主要存储介质的时代,比较流行。null*直接存取/随机存储 (kw:地址)
要求以任意次序直接读写某个记录
随机存取文件一般存放在磁盘等大容量、支持按地址存取的设备上。
为了实现直接存取,一个文件可以看作由顺序编号的物理块组成的。
直接存取文件对读或写块的次序没有限制。
用户提供给操作系统的是相对块号:相对于文件开始位置的一个位移量。
绝对块号则由操作系统换算而得到 null*索引存取 (kw:索引)
基于索引文件(?)的索引存取方法
文件中的记录不按它在文件中的位置,而按它的记录键来编址。
信息块的地址都可以通过查找记录键而换算出。
实际的系统中,大都采用多级索引,以加速记录查找过程。
散列存取:
直接由散列函数计算出特定记录的物理块位置。
是索引存取的特例null*1-10、常见操作系统的文件组织结构
Linux, Windows, Unix等OS的文件组织结构
分为两层:
操作系统层:顺序文件和随机文件。
用户自定义层:索引文件和散列文件等。
对磁盘文件而言,操作系统提供随机访问支持。
访问的时候需要给出距文件开头处的偏移量,操作系统自动根据偏移量换算出在磁盘上的物理块。
如何计算偏移量,是通过索引文件还是通过散列运算得到,是由用户设计的。null*1-11、文件系统的界面-标准的文件操作
建立文件:当用户要求把一批信息作为一个文件存放在存储器中时,使用建立操作向系统提出建立一个文件的要求。
打开文件:文件建立之后能立即使用,要通过‘打开’文件操作建立起文件和用户之间的联系。
读/写文件:文件打开以后,就可以用读/写系统调用访问文件。
文件控制:文件打开以后,把文件的读写指针定位到文件头、文件尾、或文件中的任意位置,或执行前跳、后退等各种控制操作。
关闭文件:当一个文件使用完毕后,使用者应关闭文件以便让别的使用者用此文件。
撤销文件:当一个文件不再需要时,可向系统提出撤销文件。2、文件存储和磁盘管理*2、文件存储和磁盘管理2-1、需要存储的内容
文件的具体内容:
文件的相关属性
文件名
文件的访问权限信息
文件的主人信息
文件的创建、修改等时间信息null*2-2、文件信息的存储方式
方式一:
两类信息一起存放。先文件名,后跟文件的其它属性,最后跟文件的具体内容。
对磁盘块的分配提出较高的要求,文件需要占用“连续”的磁盘块。
文件检索非常困难。
修改也非常困难,文件一旦变长,需要进行大规模的存储移动。null*方式二:
属性信息和文件内容分开存放。
文件内容以磁盘块为单位,主要结合块设备的存取特点。
属性信息集中存放。由于磁盘按块存储,可能会出现几个文件的属性信息存在一个盘块中。
文件属性和文件内容不连续存放,之间有链接关系存在。
技巧:
同一目录下的所有文件的属性信息一起存储。
属性相关信息作为上级目录的目录文件内容。null*2-3、目录的引入和组织
目录存在的好处
便于用户对文件进行分门别类、层次式的进行管理。
可以加快文件的检索速度。
便于实现用户之间的文件隔离。
便于实现对同类文件的保护。只要对目录设置特定保护权限,可以实现对目录下文件的保护null*目录的内容和存储:
目录的内容保存了文件属性,并实现了到具体文件内容的映射。
以特殊文件(目录文件)的形式存在,可以通过递归方式实现对具体文件的访问。
即:所有文件(包括一般文件和目录文件)组成一个树形层次结构,树的中间结点为目录文件,树的叶子结点为一般文件。
null*2-4、目录文件的具体内容
目录下所有文件(含子目录)的属性信息:文件名,文件属性,文件内容存储的位置。
每个文件对应的信息成为一个目录项。也就是说目录文件的内容是目录项的集合。null*每个目录项包括:
基本信息
文件名: 在一个特定的目录中具有唯一性。
文件类型: 例如文本文件,二进制文件,目标模块等。
文件组织: 系统所支持的不同组织形式。
存储信息
地址信息: 文件存放在磁盘的物理地址(例如:柱面号、磁道号或在磁盘上的块号)。两种方式:
起始地址
扇区地址数组
文件的大小,以字节、字或块计。null*存取控制信息
文件主: 拥有文件的控制权。文件主能授予和取消其他用户对文件的存取权和改变这些权限。
允许的操作: 控制读、写、执行和在网上的传输等。
使用信息
创建日期: 文件首次存放在目录中的时间。
读时间: 最后一次读文件的时间。
修改时间: 最后一次更新、插入或删除的时间。null*实例:MSDOS(FAT)的目录项结构
共32个字节
文件名:8+3字节
文件属性:1字节
保留:10字节
时间:2字节
日期:2字节
内容的起始块号(簇号):2字节
文件长度:4字节
null*2-5、目录文件的访问特点
间接式访问:
一般情况下操作系统不允许通过Read或Write直接对目录文件的内容进行访问。
如果用户(或应用程序)对目录下文件的访问导致了目录下文件属性的改变,那么操作系统会自动修改文件对应的目录项,也就是说修改目录文件的内容。
如果对目录文件的属性进行修改,那么与该目录文件的内容没有关系,实际上是:修改上级目录文件的内容。null*2-6、文件存储需要考虑的问题
占用空间是否连续
分配连续的磁盘空间:
对大文件顺序读些,访问速度快
只需保存第一个磁盘块的地址即可。
分配不连续的磁盘空间:
顺序读写稍慢(寻道时间开销大)
地址转换
较为复杂。
创建新文件时:
如何为该文件分配存储空间
如何记录磁盘块的分配状况
已分配
未分配null*2-7、分配策略
预分配:
若文件需占用连续的磁盘空间,就要采用预分配的策略。
实现思路:在文件创建的时候,为文件分配连续的磁盘空间(称为一个分区)。
特点:
无法预知文件的未来大小,可能会出现分区浪费和预留分区的大小不够。
或者:创建时要求用户说明文件的最大长度。
动态分配:
在使用时,按文件大小分配磁盘空间。
一般占有不连续的磁盘块。null*2-8、linux系统的磁盘分配实际方式
采用不连续的存储方式,如Linux下的EXT2文件系统
特例:对特殊文件,如磁盘交换文件,核心映像文件等,需要占用连续的磁盘地址空间。null*2-9、空闲磁盘块的管理
一般而言已经分配出去的磁盘块,都有目录文件的目录项的某些字段指向:
对空闲磁盘块的标示:
位图:
每个二进制位对应一个磁盘块的状态,0表示空闲块,1表示已被使用。
查找空闲磁盘块方便
占用的空间比较小
Linux的文件系统EXT2主要采用这种方式null*空闲链表:
把相邻的空闲磁盘块看成一个空闲分区
把空闲分区按链表的方式组织起来
不真正占用磁盘空间,空闲块检索的效率相对降低
Unix的文件系统主要采用这种方式
索引:
将空闲存储区当做文件一样处理。
3、Unix/Linux文件系统存储组织*3、Unix/Linux文件系统存储组织3-1、简单文件系统的存储组织回顾
特点:
目录文件的目录项中包含文件的所有属性信息、地址信息等。
不足:
目录项中字段数很多,且目录项不规则,可能存在一些可变字段。
不便于实现文件和目录共享。
目录检索速度较慢
文件属性信息分散存放,文件系统的可靠性差。null*3-2、复杂文件系统的组织思路
把文件名信息存放在目录项中
把其余的属性信息存放在一个单独的结构中。
在目录项中,保存该单独结构的地址信息null*3-3、索引节点
存放文件属性信息(除文件名)的数据结构,叫索引节点,或Inode,I节点。
I节点的结构:
struct dinode {
ushort di_mode; 文件控制模式
short di_nlink; 文件的链接数
ushort di_uid; 文件主用户标识数
ushort di_gid; 文件主同组用户组标识数
off_t di_size; 文件长度,以字节为单位
char di_addr[40]; 地址索引表,存放文件的盘块号
time_t di_atime; 文件最近一次访问时间
time_t di_mtime; 文件最近一次修改时间
time_t di_ctime; 文件创建时间
}
char di_addr[40]
每三个字节表示一个磁盘号
相当于能够表示13个磁盘号的数组
null*3-4、磁盘块的索引结构
I节点中的13个地址索引表项,对应不同的意义。
前10个表项是直接寻址。
直接存放文件前10磁盘块地址。
假定一个磁盘块1K,那么可以表示10K以内的文件
如果文件大小可用10以内磁盘块保存,后面间接寻址不使用。
第11个表项是一级间接寻址。
表示的磁盘块不是直接存放文件的内容,而是存放直接寻址表项。即表明1024/3个磁盘块号,用于存放文件内容。
该级地址最多可表示文件大小1024/3*1024。null*第12个表项是二级间接寻址。
表示的磁盘块不是直接存放文件,而是存放一级间接寻址表项。即表明1024/3个磁盘块号,用于存放一级寻址表项。
该级地址最多可表示文件大小1024/3*1024/3*1024。
第13个表项是三级间接寻址。
表示的磁盘块不是直接存放文件,而是存放二级间接寻址表项。即表明1024/3个磁盘块号,用于存放二级寻址表项。
该级地址最多可表示文件大小1024/3*1024/3*1024/3*1024。null*图6-4 UNIX文件索引结构…………………………………null*3-5、目录项结构
每个目录项由2字节的I节点号和 14字节的文件名分量组成,一些UNIX系统的文件名分量可扩展。
struct direct {
ino_t d_ino; /* 对应文件的I节点 */
char d_name [14]; /* 文件名 */
}null*3-6目录结构
UNIX将同一目录下的所有文件的目录项数据组成一个目录文件
目录文件和一般文件用同样的方式存储,只是目录文件的内容是目录下所有文件/子目录对应的目录项。
目录文件中的前二个目录项的文件名比较特殊,它们为“.”和“.. ”,分别表示当前目录和父目录,它们的I节点号就是当前目录文件的I节点号和上一级目录文件的I节点号,便于向上回溯。
根目录文件是无名的,也没有目录项,它对应的I节点在磁盘固定位置。
从根开始,根目录的下级目录的名字存放在根目录文件的目录项中,并各有一个指针指示下级目录文件的I节点。如此一级一级扩展下去,直至最底层的数据文件或空的目录文件,构成了整个UNIX的树型目录结构null*I节点目录
文件块
目录项n目录项1文件物理盘块图6-6 UNIX目录系统结构di_addr [ ]di_addr [ ]目录项目录项根目录
文件块
目录项n目录项1根目录文件
I节点i_addr [ ]null*3-7、文件和目录共享
不同目录项(同一目录文件或不同的目录文件中)指向同一个索引节点
一个文件可以有多个不同的名字
每个名字叫做一个链接
通过I节点方便实现文件共享。null*3-8、文件搜索
路径表示方式:
绝对路径:从根目录到文件的具体位置
相对路径:从当前目录到文件的具体位置null*绝对路径搜索:如/etc/passwd,
系统先得到根I节点,再根据其中的地址索引表将根目录文件的盘块内容读入内存,
逐项比较,看其中是否有一个目录项的文件名与根的下一层路径名分量,如etc,相匹配。
找到匹配项后,根据该项的I节点号再得到下层目录文件的I节点。通过该I节点的地址索引表,读入etc目录文件的物理盘块。
在该盘块中再逐项比较,直至找到文件名为passwd的目录项并获得passwd文件的I节点
读取passwd文件的各个物理盘块内容
相对路径搜索:
除了起始搜索点是当前目录项的I节点外,其余与绝对路径搜索并无不同。null*3-9、UNIX文件系统在磁盘的存储布局
分布概述:
一个物理磁盘能够被划分成多个逻辑分区,相当于一个逻辑盘。对每一个逻辑盘,盘块的物理地址是连续的。
可以把一个逻辑盘的存储地址空间堪称一个一维的线性空间。
一个文件系统对应一个逻辑盘。一个物理磁盘上可以同时存在多个文件系统。null*在一个逻辑盘上,其存储空间安排如:
null*引导块:
在块号为0的引导块中包含操作系统的自举程序
该块不属于文件系统一部分。
有些逻辑分区上没有这一块的内容
进程对换区:
连续磁盘区域。用于是换入/换出,作为内存的扩充。
该块不属于文件系统的一部分。
有些系统,如Linux,可以以单独的一个逻辑盘作为交换区null*超级块
用于存放文件系统的核心数据
各部分的盘块分布
空闲节点数,空闲节点表
空闲盘块数,空闲盘块索引
文件系统的类型、版本号,文件系统的状态
超级块在文件系统启动时,为了快速更新,被复制到内存一份。定时更新磁盘上超级块
为了保证超级块的安全性,超级块在磁盘上有备份,用于文件系统恢复。null*超级块结构:
struct filsys {
ushort s_isize; /* 磁盘索引节点区所占用的盘块总数 */
daddr_t s_fsize; /* 整个文件系统的盘块总数 */
Short s_nfree; /* 直接管理的空闲块数目 */
daddr_t s_free[NICFREE]; /* 空闲块索引表 */
Short s_ninode; /*直接管理的空闲索引节点数 */
ino_t s_inode[NICINOD]; /* 空闲I节点索引表 */
Char s_flock; /* 处理空闲块表时的加锁标志位 */
Char s_ilock; /* 处理空闲I节点表时的加锁标志位 */
Char s_fmod; /* 文件系统超级块被修改标志 */
daddr_t s_tfree; /* 空闲数据块总数 */
ino_t s_tinode; /* 空闲索引节点总数 */
}
null*空闲索引节点管理
文件的索引节点按编号依次存放在磁盘的I节点区
每个索引节点存在相应的状态标示:空闲或已分配。
按顺序检索可以发现空闲节点。
为加快对空闲索引节点的查找
设置一个空闲索引节点栈,保存一部分空闲节点。
对索引节点的申请和释放,主要在栈中完成。
如果栈为空,会按顺序检索空闲节点,试图把栈重新装满。
如果栈满,则直接释放不再入栈。null*空闲磁盘块的管理
所有空闲磁盘块以多叉(50)树的方式组织。
树的每个叶子节点对应一个空闲磁盘块
树的每个中间节点存储在一个空闲磁盘块中,其内容表示下层的多(50)个磁盘块号。null*图6-11 空闲文件存储块的分组链式索引filsys………s_nfree:25
s_free [0]
:
s_free [24]s_nfree:50
s_free [0]:0
s_free [1]
:
s_free [49]s_nfree:50
s_free [0]
:
:
s_free [49]s_nfree:50
s_free [0]
:
:
s_free [49]…null*3-10、UNIX的文件打开管理
内存中的目录结构树
必要性:
访问一个文件时,系统要从根目录或当前目录出发,循序读取和搜索各级目录文件磁盘I节点,索引结构等,找到文件物理块号后再存取文件数据。
涉及多次磁盘操作,速度慢。
技术思路:
在内存中,保存磁盘上的目录结构树的副本
内存中并不是完整的副本,而是一部分:
内容容量的限制
根据局部性原理,保存一部分就能起到很好的效果null*内存索引节点
存在的必要
文件打开后,索引节点可能被频繁访问,需要提高访问速度。
实现多文件系统支持的一种技术手段。
可以扩充一些字段,实现一些动态信息
null*具体结构
struct inode {
struct inod *i_forw; 内存I节点的散列队列双向循环勾连指针
struct inod *i_back;
char i_flag; 状态标志,如锁标志、修改标志等
cnt_t i_count; 引用计数,表示该文件打开了几次
dev_t i_dev; 文件所在的设备号
ino_t i_number; 对应的磁盘索引节点号
struct {
union {
daddr_t i_a[13]; 常规文件或目录文件的地址索引表
short i_f[26] 管道文件的地址索引表
}i_p;
daddr_t i_l 最近一次读入的文件逻辑块,用于预读
} i_blk;
null*文件控制块
文件被打开一次,就分配一个相应的文件控制块。主要用于保存文件打开后产生一些动态信息。
存在的必要(为何动态信息不存放在内存索引节点中)
内存索引节点主要存在文件相关的静态信息
便于实现一个文件同时被多个进程打开。
null*具体结构
struct file {
char f_flag; 操作方式,如写、读、追加写等
cnt_t f_count; 共享该file结构的进程数
union {
struct inode *f_uinode; 指向内存I节点
struct file *f_unext; 空闲file的链接指针
} f_up;
union {
off_t f_off; 读写位置指针
} f_un;
};null*进程的打开文件表
进程打开文件表或称打开文件描述字表是进程扩充控制块user结构中一个指针数组struct file *u_ofile[NOFILE]
每个表项指向一个打开的文件(即文件控制块)
进程在打开文件时按下标序由低至高顺次使用该数组中的某一空闲项,在该表项中填入打开文件控制块file结构变量的地址,打开文件描述字的值就是该空闲项的下标值
一般情况下,子进程继承父进程打开的文件。二者的打开文件表是相同的。4、文件相关的系统调用*4、文件相关的系统调用4-1、文件创建
Creat:创建一个新的空文件
调用格式:
fd=creat(char * pathname, int mode);
int fd, mode;
char *pathname;
参数:
Pathname:要创建文件的带路径的文件名。
mode是以二进制的位值为该文件设置的存取控制权限。
低9位以3位为一组,由高至低位分别表示文件主,文件主同组用户和其他用户对该文件是否拥有读、写、执行权限。
高三位分别:
粘贴位:
组标示控制位
S位null*返回值:
fd中存放文件创建成功后系统返回的整数值,称为打开文件标识数(或称描述字)
如创建失败,fd为-1
说明:
创建成功后,该文件为打开状态,而且是写状态。
若已存在同名文件,如原同名文件可写,则相当于先清空原来文件的内容。null*4-2、文件打开
Open:打开一个已经存在的文件。在使用文件前都需要打开相应的文件
调用格式:
fd=open (pathname,flags);
int fd, flags;
char *pathname
参数描述:
Pathname:所要打开文件的文件名(含路径)null*Flags:表示打开后要对文件进行的操作类型。
O_RDONLY (0) 对文件进行读操作。
O_WRONLY (1) 对文件进行写操作。
O_RDWR (2) 对文件既可以读也可以写。
O_NDELAY (4) 打开管道文件时是否要等待。
O_APPEND (8) 对文件进行添加写操作。
返回值:
Fd:整型值,表示文件打开标示数(文件描述符)
说明:
若文件不存在,且打开目的为写( O_WRONLY ),视O_CREAT的设置与否,可能会直接创建一个文件并打开。文件的访问权限设置采用默认设置。
若不用默认设置可调用fd=open (pathname, flags,mode);
文件打开后,一般情况:读写指针默认为0位置。null*4-3、文件关闭
Close:关闭一个已经打开的文件
调用格式:
Ret = Close(fd)
Int fd,ret
参数:
Fd:打开文件的文件描述符
返回值:
成功为0
不成功为-1
说明:
当程序运行终止时,操作系统会关闭该进程打开的所有文件null*4-4、创建文件链接
Link:为一个已经存在的文件创建一个链接,相当于再起一个新的文件名
描述
Ret = link(oldname,newname)
Int ret
Char * oldname,newname
返回值:
0表示成功
-1表示不成功
说明:
和Windows下的快捷方式不同,新链接一旦创建成功,和原来的文件名(原链接)在没有联系。不存在新链接依赖于旧链接的问题null*4-5,删除文件/链接
Unlink:删除一个文件连接
描述:
Ret = unlink(filename)
Int ret
Char * filename
返回值:
0表示成功
-1表示不成功
说明:
删除一个文件链接,如果该文件对应的链接数等于1,就直接删除该文件。null*4-6、读文件
Read:从文件中读数据
描述:
size = read(fd,buffer,nbytes)
Int size, nbytes, fd
Char *buffer
参数:
Fd:被读文件的文件描述符
Buffer:从文件中读出的数据放到的缓冲区
Nbytes:希望从文件中读出的数据长度,字节数表示
返回值:
成功读出的数据长度
如果读不成功,为-1
说明:
读成功后,fd的读指针后移相应的字节数。null*4-7、写文件
write:写数据到文件
描述:
size = write(fd,buffer,nbytes)
Int size, nbytes, fd
Char *buffer
参数:
Fd:要写文件的文件描述符
Buffer:把哪个缓冲区中的内容写到文件
Nbytes:希望写的数据长度,字节数表示
返回值:
成功写入的数据长度
如果写不成功,为-1
说明:
写成功后,fd的写指针后移相应的字节数。
null*4-8、三个特殊文件的读写
标准输入/输出文件
为便于应用程序和标准终端进行输入/输出,标准终端也以文件的形式存在。而且对应的文件在进程创建后就已处于打开的状态。
0号 标准读文件代表键盘输入
1号 标准写文件代表屏幕显示
2号 标准错误输出文件,是程序的运行时的出错信息,写至屏幕上null*4-9、调整文件读写指针
Lseek:改变文件的读写指针位置,实现随机读写
描述:
lseek(fd, offset, whence)
参数:
Fd:文件描述符
Offset:字节偏移量
Whence:移动方式的参考点
0:参考点为文件头
1:参考点为当前位置
2:参考点为文件末尾
返回值:
文件读写指针位置。
说明:
Whence为0时,offset不能为负值
Whence为2时,offset不能为正值null*4-10,创建其他类型文件
Mknod:创建特殊文件,目录,管道或设备文件
描述:
Int mknod(filename,mode,device)
参数
Filename:要创建文件的文件名
Mode:文件的存取控制属性
Device:设备号(只在创建设备文件时有效)
返回值
0:表示成功
-1:表示创建失败null*4-11、改变文件的权限chmod
改变一个文件或目录的许可权,调用格式为
chmod (pathname, mode);
char *pathname;
int mode;
mode的二进制位定义同creat系统调用。null*4-12、复制文件描述字dup
为一个已打开的文件再分配一个新的文件描述字,使多个文件描述字可与同一个文件相联系,在构造shell的管道线时这个调用很重要。调用格式为
newfd=dup (fd);
int fd, newfd;
执行本调用时,核心为已打开的文件fd在打 开文件表中再分配可用的文件描述字,并返回给执行进程。null*4-13、查询文件的状态stat与fstat
返回文件的类型、大小、所有者、存取权限,联接数等信息。这些信息是从文件的索引节点中读出来的。调用格式有两种:
stat (pathname, buf);
fstat (fd, buf);
char *pathname;
struct stat *buf;
int fd;
前一个调用所指文件是以UNIX的路径名形式给出,因此能返回文件系统中存在文件的状态,后一个调用是以文件描述字的形式给出,故只能用于已打开的文件。后一种调用执行的速度要比前一种快。返回的文件状态存放在stat类型的结构中。
null*4-14、对已打开的文件进行控制
fcntl (fd, cmd, arg);
int fd, cmd, arg;
cmd为对文件的控制模式null*4-15、设置权限屏蔽字
umask调用可以设置或改变进程所创建文件的屏蔽字
格式:umask(mode)
说明:
如果在该调用后,进程创建文件时,如果没有明确指明文件初始权限模式,就用该调用设置的模式
如果在open调用中,已经明确了权限模式,则该设置对这次文件创建不起作用。null*4-16、目录文件的读操作
Open可以打开一个目录文件
获取目录文件中的目录项
Int getdents(int fd, struct dirent *dirp, int count)5、文件相关的标准I/O库*5、文件相关的标准I/O库5-1、标准I/O库的存在背景
完成文件基本操作的系统调用提供的只是字节序列方式的最基本的功能,不能完成任何格式转化。使用起来相对而言比较麻烦
不便于实现源程序之间的移植。实际上,两个OS比较难以在系统调用界面上实现完全兼容。
5-2、标准I/O库的实现思路
在源程序和系统调用层之间实现一层文件操作相关的库,用于实现对系统调用的封装。null*5-3、标准I/O库的主要功能
为了提供功能更强和使用更方便的输入和输出操作。
通过用户态空间的自动缓冲机构以及数据类型转化和格式化的输入输出,提供了效率高、功能强和可移植的文件访问或字符串处理功能
通过一个FILE类型结构建立与打开文件的联系,称为流(stream)null*5-4、流文件的大致实现
结构:
typedef struct _iobuf {
unsigned char *_ptr; 缓冲区内下一字符地址
int _cnt; 缓冲区中_ptr所指位置后剩余字符数
unsigned char *_base; 缓冲区起始地址
char _flag; 存取方式,如读或/和写
char _file; 文件描述字
} FILE;
file用于存放打开文件的描述字
写操作:输入的字节数据逐个放入缓冲区中,并相应地调整_ptr和_cnt之值。如果缓冲区存满了,例行程序再通过系统调用write把缓冲区内容写入_file指示的文件中。
读操作:从缓冲区中读数据,当缓冲区空了时,就通过系统调用read从文件中再读入一个缓冲区的数据。
null*图6-3流文件操作与系统调用间的关系用
户
态
与
核
心
态
切
换用户程序标准I/O库核心程序流文件操作用户态空间核心态空间块设备
读写块设备
驱动系统调用用户
程序fread ( )
fwrite ( )文件
卷用户态
缓冲区read ( )
write ( )核心态
缓冲区null*5-5、流文件打开
使用描述
FILE *fp;
fp=fopen (pathname, type);
char *pathname, *type;
参数:
Pathname:文件名
Type:打开方式。
r 打开文件用于只读。
w 建立文件或把已存在文件截为空文件,用于只写。
a 打开文件用于文件尾的追加写。
说明:
如果打开成功,把它与一个流联系起来,并返回标识该流的FILE结构的指针。如fopen失败,返回NULL。参数type可取下列的基本值:
与0#,1#,2#三个标准的打开文件描述字相联系,标准I/O库提供了三个不需要打开的流,并用下列的FILE指针标识:
stdin 标准输入流
stdout 标准输出流
stderr 错误输出流
null*5-6、流文件关闭
使用描述
fclose(fp);
功能说明:
该命令刷新与文件相关的缓冲区,关闭已打开的文件并释放FILE结构。如果不显式执行该命令,进程运行结束后关闭所有打开的流文件。null*5-7、流文件读写
使用描述:
n=fread(buf,size,nitems,fp);
n=fwrite(buf,size,nitems,fp);
int n,size,nitems;
char *buf;
FILE *fp;
功能描述:
fread从fp指定的输入流文件中将nitems个大小为size的数据对象读入buf所指向的存储区中,返回值n给出了成功读出的数据对象个数。
fwrite将nitems个大小为size的数据对象从buf所指的存储区写到fp所指定的输出流文件中。返回值n给出了实际写入的数据对象个数。
其他说明
fread与fwrite是二进制数据的读写方法
与具体机器的数据内部存储方法(如一个字的高、低位字节次序)有关null*5-8、流文件读写效率
对比举例:
循环write (fd, buf, 1)
循环fwrite (buf, 1, 1, fp)
分析:
前者,每写一次都需要完成一次系统调用。
后者,每执行一次往库缓冲区中写一个字节,待缓冲区写满后,才执行系统调用完成数据写(所有缓冲区的内容)
结论:
由于前者要频繁切换系统状态(核心态和用户态),因此后者的效率在这种情况下要高得多null*5-9、调整和获得流文件的读写位置
使用描述:
fseek (fp, offset, whence);
rewind (fp);
position = ftell (fp);
FILE *fp;
long offset, position;
int whence;
功能说明:
rewind将文件读写位置指针调整到文件头
ftell返回流中的当前位置
fseek同lseek功能类似,只是针对流文件。null*5-10、格式化输入/输出
特征对比
二进制I/O与机器特征有关,需要用户熟悉机器特征并进行正确解析
格式化I/O可以由库函数直接完成相应的解析
使用格式1:
fscanf (fp, format
[, arg1, arg2, … argn] );
fprintf (fp, format
[, arg1, arg2, … argn] );
FILE *fp;
char *format;
使用格式2:直接同终端I/O
scanf (format [, arg1, arg2, … argn] );
printf (format [, arg1, arg2, … argn] );
char *format;null*5-11、单字符I/O
每次只要从流文件中读入一个字符或向流文件中输出一个字符
使用描述1:
c = fgetc (fp) 和
fputc (c, fp)
char c;
FILE *fp;null*使用描述2:
c = getc (stdin);
putc (c, stdout);
使用描述3:
c = getchar( );
putchar(c);
使用描述:回退刚刚输入的一个字符
ungetc(c, fp);
char c;
FILE *fp;null*5-12、行输入/输出
使用描述1:
retstring = fgets(buf, size, fp);
fputs(string, fp);
char *buf, *retsting, *string;
int size;
FILE *fp;
使用描述2:标准I/O
gets(buf)
Put(buf)
说明
fgets从流fp中读字符,直至读到换行符或文件结束,但一次最多读size个字符。读出的字符连同换行符存入缓冲区buf中。返回指向buf的指针。
fputs将一行字符串string写入流文件fp中。null*5-13、存储区格式化
使用描述:
sscanf (buf, format, arg1
[, arg2, …, argn]);
sprintf (buf, format
[, arg1, arg2, …, argn]);
char *buf, *format;
描述:
sscanf函数中各个参数所需的值不是从终端或文件中输入,而是取自缓冲区buf中。
sprintf函数则将各个参数的值存入缓冲区buf中
格式说明串format则规定了数据传送时的格式变换null*5-14、程序执行
使用描述:
retval = system (command);
char *command;
int retval;
说明:
先创建一个子进程,然后让子进程改换自己的图像
并由shell 执行参数所指定的命令
主进程等待子进程执行完之后,再继续执行。6、管道文件和通信*6、管道文件和通信6-1、管道的基本概念
一种进程间的通信方式。
能够在进程间传递大量的顺序信息:像一队列,一进程在尾部顺序写数据,另一进程从头部顺序读数据。
数据的写入和读出以先进先出的方式进行,并由系统自动地处理两个进程间的调度、同步和数据缓冲,这类文件就称为管道(pipe)文件,简称管道,或称FIFO
读、写的具体方式和读写文件没有任何区别。
对上层用户而言,管道分为两个级别:
操作系统级:同时执行的两个进程进行通信
Shell命令级:ls | morenull*6-2、无名管道的创建
使用系统调用pipe创建。
只能在与创建pipe的进程同一进程族内传递数据,常用于父子进程间的通信
具体方法:
int fd[2],retv;
retv=pipe(fd);null*6-3、无名管道的实现
创建管道时,核心首先为其在管道设备文件系统中分配一个磁盘I节点和一个相应的内存I节点
再分配两个分别用于读打开和写打开的file结构
进程打开表中分配两个文件描述字表项,一个指向读打开file结构,一个指向写打开file结构,其中,在fd[0]中返回的是读端文件描述字,在fd[1]中返回的是写端文件描述字。fd [0]fd [1]读数据写数据null*6-4、无名管道的读写
管道创建后,就可以通过两个fd进行读写来完成通信。一般情况下,通过一个(或多个)进程写,另一个(或多个)进程读。
管道类似于循环缓冲区,其长度最大为10个磁盘块的大小。
初始时,读指针和写指针都在零位置。
每当有数据写入时,写指针自动增加,整个缓冲写满后就不能再写。
每当有数据读出时,读指针自动增加。读指针不能超过写指针,赶上写指针时表示没有东西可读。
null*i_frptr i_fwptr90····················· 图6-13 循环队列机构的管道null*6-5、无名管道的关闭
无名管道的关闭和关闭普通文件没有区别。
如果两个进程同时对一管道进行写/读,那么在一个进程中关闭fd[1]/fd[0],并不影响另外一个进程。
如果所有的写进程关闭,表示该管道关闭。核心将唤醒所有等待读的进程。
如果所有的读进程关闭,表示该管道关闭。核心通过信号告知写进程。null*6-6、无名管道的应用实例:父进程向子进程传递信息
main ( )
{
char *msg = "A message from parent. "
int chan [2];
char buf [100];
pipe (chan);
if (fork ( )) {
close (chan [0]); /* 父进程关闭管道读端 */
write (chan [1], msg, strlen (msg)+1);
/* 写管道 */
close (chan [1]);
} else {
close (chan [1]);
read (chan [0], buf, strlen (msg)+1)
/* 子进程读管道 */
printf ("Child Proedss:% s\n", buf);
close (chan [0]);
}
}
null*6-7、有名管道的概念
无名管道的通信特点
只便于在一组进程间进行通信。常用于父子进程。
无名管道是动态的,通信的进程要同时存在。
在文件系统中,不长久存在。
有名管道:
缓冲区在磁盘上有副本,类似于临时文件,在磁盘上存在相应的I节点和目录项,也有文件名和路径名。
象普通文件一样是静态的,需要创建和删除
管道的基本特征仍然存在:FIFO
有名管道类似于只支持FIFO读写方式的特殊文件
无关的进程就可以通过有名管道进行通信null*6-8、有名管道的创建
目录、特别文件和有名管道文件只能用mknod创建
创建普通文件、目录和特别文件的mknod调用只对超级用户开放
所有的用户都能用mknod创建有名管道文件
例如:
int mknod(pathname,mode,device);
char *pathname; /* 有名管道文件名 */
int mode,device; /* 存取限权等,设备号 */
创建普通文件、目录和有名管道文件时参数device被忽略。例如,创建一个所有的用户都能读和写的有名管道文件的系统调用为:
mknod("fifos",S_IFIFO|0666,0)null*6-9、有名管道的控制
打开:
通过Open打开,和普通文件一样
读写:
通过open获得的fd,实现读写,和普通文件一样
读指针不能超过写指针
关闭
和关闭普通文件一样,调用close
删除
调用unlink,和普通文件一样null*6-10、有名管道的使用实例
main( )
{ mknod ("fifo", S_IFIFO|0666,0);
fd = open ("fifo",O_WRONLY);
while (gets(buf)!=NULL)
write (fd, buf, strlen(buf)+1);
close (fd);
}
main ( )
{ fd = open ("fifo",O_RDONLY | O_NDELAY);
while ((n = read (fd,buf,sizeof(buf) ))! = -1)
if (n = = 0)
sleep (NAPTIME)
else puts (buf);
close (fd);
}7、Linux文件系统*7、Linux文件系统7-1、文件系统概述
支持多种文件系统:Ext2,ms-dos, FAT32,NTFS等
Linux可以把多个文件系统(同类型或不同类型)动态构成一个单一的树状层次结构,呈现在用户面前
Linux通过mount调用把具体的文件系统(树型层次结构)挂在全局树型结构的某个节点上。
操作系统启动时,或按设置自动挂装一个主文件系统。其树型层次结构作为系统的主树型层次结构。
其它的文件系统可以动态(随时挂装和卸载)挂在主树型结构的任意节点。
同一个磁盘(含特定文件系统)每次挂装点的选择是任意的。null*7-2、虚拟文件系统
背景和目标
Linux需要支持多种文件系统。
屏蔽下层的具体文件系统,向上提供统一的文件服务。
主要思路
在具体文件系统和操作系统的文件服务接口间实现虚拟层
对下层的具体文件系统进行统一封装和细节屏蔽
对上层提供统一的文件服务接口
核心实现:
对一些文件系统的具体实现,如果实现与具体文件系统无关,把这些实现统一到VFS层。如:一些结构的缓冲,索引节点
当一个进程调用文件系统例程时,内核调用VFS函数 (这个函数是和具体结构无关的),并将这个调用传递给物理文件系统中的相应函数,该函数和具体的物理结构有关。null*硬盘控制器I/O调用硬件层用户进程系统调用界面VFSMinixDOSextext2Buffer Cache设备驱动程序Linux内核层系统调用(trap)Inode cache目录cache 图6-15 Linux虚拟文件系统
null*7-3、Ext2文件系统
概述:
为Linux设计的文件系统。目前主要在Linux系统得到支持
支持Unix中的多种文件类型:常规文件、目录文件、设备文件、链接文件、管道文件
支持大磁盘的分区
支持大文件。
支持长文件名null*磁盘块的大小,可以选择:1024、2048、4096
文件组织结构和UNIX文件系统基本相近:
也存在I节点
目录项的组织也类似
磁盘物理结构布局:
引导区
多个块组。每个块组包含
全局信息(可能冗余):超级块
组描述符表(冗余):每个记录了一个块组的块位图位置、inode位图位置、inode节点位置、空闲块数、inode数、目录数等内容
块位图:表示块组内数据块的空闲状况
索引节点表:表示所有可用的索引节点
索引节点位图:表示索引节点的空闲状况
数据块:用于存储文件(包含目录文件)的内容null*目录项:
长度可变,因为支持长文件名
内容:
文件名长度
文件名
索引节点号
整个目录项长度习题:*习题:P202/P177
3,9,10
列举文件系统面向用户的主要功能。谢谢*谢谢