第10章 系统级I/O
第10章 系统级I/O
10.1 Unix I/O
一个Unix文件就是一个m个字节的序列:B0,B1,…,BK,…,Bm-1
Unix I/O:一种将设备优雅地映射为文件的方式,允许Unix内核引出一个简单、低级的应用接口,这使得所有的输入输出都能以一种统一且一致的方式来执行:
- 打开文件:
- 内核返回一个小的非负整数,叫做描述符。
- Unix外壳创建的每个进程开始时都有三个打开的文件:标准输入(描述符为0)、标准输出(描述符为1)、标准错误(描述符为2)。
- 改变当前文件位置:
- 对于每个打开的文件,内核保持着一个文件位置K,初始为0。
- 这个文件位置是从文件开头起始的字节偏移量。
- 应用程序能够通过执行seek操作,显示地设置文件当前位置为K。
- 读写文件:
- 读操作:从文件拷贝n>0个字节到存储器,从当前文件位置K开始,然后将K增加到k+n。
- 写操作:从存储器拷贝n>0个字节到一个文件,从当前文件位置K开始然后更新K 。
- 关闭文件:
当应用完成了对文件的访问之后,他就通知内核关闭这个文件。
10.2 打开和关闭文件
进程通过调用open函数来打开一个已存在的文件或者创建一个新文件的:R
open函数将filename转换成一个文件描述符,并且返回描述符数字。返回的描述符总是在进程中没有打开的最小描述符。
Flags参数指明了进程打算如何访问这个文件:
- O_RDONLY:只读
- O_WRONLY:只写
- O_RDWR:可读可写
Flags参数也可以是一个或者更多位掩码的或,为写提供给一些额外的指示:
- O_CREAT:如果文件不存在,就创建它的一个截断的(空)文件。
- O_TRUNC: 如果文件已经存在,就截断他。
- O_APPEN D:在每次写操作前,设置文件位置到文件的结尾处。
Mode参数指定了新文件的访问权限位。
最后进程通过调用close函数关闭一个打开的文件。
关闭一个已关闭的描述符会出错。
10.3 读和写文件
应用程序是通过分别调用read和write函数来执行输入和输出的。
Read函数从描述符为fd的当前文件位置拷贝最多n个字节到存储器位置buf。若返回值既不是0,也不是-1,则返回值表示的是实际传送的字节数量。
Write函数从存储器位置buf拷贝至多n个字节到描述符fd的当前文件位置。
在某些情况下,read和write传送的字节比应用程序要求的要少。这些不足值不表示有错误。出现这种情况原因如下:
- 读时遇到EOF
- 从终端读文本行
- 读和写网络套接字(socket)
10. 4 用RIO包健壮地读写
RIO包会自动为你处理上文中所述的不足值。
RIO提供了两类不同的函数:
- 无缓冲的输入输出函数。
- 带缓冲的输入函数。
10.4.1 RIO的无缓冲的输入输出函数
通过调用rio_readn和rio_writen函数,应用程序可以在存储器和文件之间直接传送数据。
注意:如果rio_readn和rio_writen函数被一个从应用信号处理程序的返回中断,那么每个函数都会手动地重启read或write。
10.4.2 RIO的带缓冲的输入函数
另一种更好的方法就是调用一个包装函数(rio_readlineb)他从一个内部读缓冲区拷贝一个文本行,当缓冲区变空时,会自动地调用read重新填满缓冲区。
每打开一个描述符都会调用一次rio_ readlineb函数。它将描述符fd和地址rp处的一个类型为rio_t的读缓冲区联系起来。
RIO读程序的核心如下 rio_read函数:
10. 5 读取文件数据
应用程序能够通过调用stat 和 fstat函数,检索到关于文件的信息(元数据)。
Stat函数以一个文件名作为输入,并填写一个stat数据中的各个成员。Fstat函数是相似的,只不过是以文件描述符而不是文件名作为输入。
St_size 成员包含了文件的字节数大小。St_mode成员则编码了文件访问许可位和文件类型。Unix识别大量不同的文件类型。Unix提供的宏指令根据st_mode成员来确定文件的类型。
10. 6 共享文件
内核用三个相关的数据结构来表示打开的文件:
- 描述符表。
- 文件表。
- V-node表。