预计学习时间:6h

实际花费时间:9.5h

 

第十章 系统级I/O

  输入输出(I/O)是在主存和外部设备之间拷贝数据的过程。

一、Unix I/O

  一个Unix文件就是一个m个字节的序列,所有的I/O设备都被模型化为文件,而所有的输入和输出都被当做对应文件的读和写来执行。

 1.打开文件

    · 一个应用程序通过要求内核打开相应的文件来宣告它想要访问一个I/O设备。内核返回一个小的非负整数,称为描述符,在后续对此文件的所有操作中标识这个文件。

    · Unix外壳创建的每个进程开始时都有三个打开的文件:标准输入(0)、标准输出(1)、标准错误(2)。

    · 当打开一个文件的最初时候文件的偏移量为0。通过seek操作,可以显示的设置文件的当前位置为k。

 2.读写文件

    · 读操作:从文件拷贝n>0个字节到存储器,从当前文件位置k开始,增加到k+n。当k>=文件长度大小时会触发一个称为end-of-file(EOF)的条件。

    · 写操作:从存储器拷贝n>0个字节到一个文件,从当前文件位置k开始,然后更新k。

 3.关闭文件

    · 内核释放文件打开时创建的数据结构。

 

二、打开和关闭文件

 1.open函数
  ·进程是通过调用open函数来打开一个已存在的文件或者创建一个新文件的:
     #include <sys/types.h>

     #include <sys/stat.h>

     #include <fcntl.h>

     int open(char *filename, int flags, mode_t mode);
                                  返回:若成功则为新文件描述符,如果出错,返回值为-1.
     open函数将filename转换为一个文件描述符,并且返回描述符数字。返回的描述符总是在进程中当前没有打开的最小描述符。     

 

  ·flags参数指明进程打算如何访问这个文件:

      O_RDONLY:只读
      O_WRONLY:只写
      O_RDWR:可读可写

 

      O_CREAT:文件不存在,就创建新文件
      O_TRUNC:如果文件存在,就截断它
      O_APPEND:写操作前设置文件位置到结尾处

  ·mode指定了新文件的访问权限位,符号名称如下:

 2.close函数
  · 进程通过调用close函数关闭一个打开的文件
    #include <unistd.h>
    int close(int fd);

            ·返回:成功返回0,出错返回-1
  ·关闭一个已经关闭的描述符会出错

三、读和写文件

    · 读文件:read函数从描述符为fd的当前文件位置拷贝最多n个字节到存储器位置buf。返回值表示实际传送的字节数量,错误返回-1,EOF返回0。
    · 写文件:write函数从存储器位置buf拷贝至多n个字节到描述符fd的当前文件位置。

    · 通过lseek函数可以显式的修改当前文件的位置

 【不足值】
    不足值指在某些情况下,read和write传送的字节比应用程序要求的要少,原因如下:
     · 读的时候遇到EOF
     · 从终端读文本行
     · 读和写socket

四、用RIO包健壮地读写

    RIO,Robust I/O,自动处理不足值。RIO包提供了方便、健壮好高效的I/O。
 1.RIO的无缓冲的输入输出函数。
    · 通过调用rio_readn函数和rio_writen函数,应用程序可以在存储器和文件之间直接传送数据。
        #include "csapp.h"

        ssize_t rio_readn(int fd, void *usrbuf, size_t n);

        ssize_t rio_writen(int fd, void *usrbuf, size_t n);

                        返回:若成功则为返回传送的字节数,若EOF则为0(只对rio_readn而言),出错为-1

 2.RIO的带缓冲的输入函数

    一个文本行就是一个由换行符结尾的ASCII码字符序列。

    rio _ readlineb和rio _ readnb函数从一个内部读缓冲区拷贝一个文本行,当缓冲区变空时,会自动调用read重新填满缓冲区。

      #include "csapp.h"

      void rio_readinitb(rio_t *rp, int fd);

                              返回:无。

     ssize_t rio_readlineb(rio_t *rp,void *usrbuf, size_t maxlen);
     ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n);

                              返回:成功则返回传送的字节数,若EO则F为0,出错则为-1。

    · 打开每一个描述符都会调用一次rio _ readinitb函数,他将描述符fd和地址rp处的一个类型为rio _ t的读缓冲区联系起来。
    · 带缓冲的函数的调用不应该和无缓冲的rio _ readn交叉使用。

 

五、读取文件元数据

  应用程序能通过调用stat和fstat函数,检索到关于文件的信息(元数据)。stat函数以一个文件名作为输入,fstat函数以文件描述符作为输入。
      #include <unistd.h>

      #include <sys/stat.h>

      int stat(const char *filename,struct stat *buf);

      int fstat(int fd,struct stat *buf);

                                返回:若成功则为0,若出错则为-1。  

  st _ size成员包含了文件的字节数大小。st _ mode成员则编码了文件访问许可位和文件类型。

  · 普通文件包括某种类型的二进制或文本数据。
  · 目录文件包含关于其他文件的信息。
  · 套接字是一种用来通过网络与其他进程通信的文件。

 

六、共享文件

  内核用三个相关的数据结构来表示其打开的文件:

    · 描述符表:表项由进程打开的文件描述符来索引的,每个打开的描述符表指向文件表中的一个表项,每个进程有其独立的描述符表。

    · 文件表:打开文件的集合是由一张文件表来表示的,所有的进程共享这张表。包括:当前的文件位置、引用计数、以及一个指向v-node表中对应表项的指针。

    · v-node表:每个表项包含stat结构中的大多数信息,;包括st_mode和st_size成员,所有进程共享。

 

七、I/O重定向

  · I/O重定向操作符,允许用户将磁盘文件和标准输入输出联系起来。

     unix > ls > foo.txt
  · dup2函数拷贝描述符表表项oldfd到描述符表项newfd,覆盖描述符表表项newfd以前的内容。如果newfd已经打开,dup2会在拷贝oldfd之前关闭newfd。
     #include <unistd.h>
     int dup2(int oldfd,int newfd);

                      返回:若成功则为非负的描述符,若出错则为-1。

 

八、标准I/O

 

 1.标准I/O库

    ANSI C定义了一组高级输入输出函数,称为标准I/O库,包含:
       · fopen、fclose,打开和关闭文件

       · fread、fwrite,读和写字节

       · fgets、fputs,读和写字符串

       · scanf、printf,复杂的格式化的I/O函数

 2.流

    · 标准I/O库将一个打开的文件模型化为一个流,也就是一个指向FILE类型的结构的指针。

    ·  类型为file的流是对文件描述符和流缓冲区的抽象,目的是使开销较高的Unix I/O系统调用的数量尽可能小。

    · 每个ANSI C程序开始的时候都有三个打开的流:stdin、stdout、stderr,对应于标准输入、标准输出和标准错误,定义如下:

        #include <stdio.h>
        extern FILE *stdin; /*标准输入,文件描述符为0*/
        extern FILE *stdout; /*标准输出,文件描述符为1*/
        extern FILE *stderr; /*标准错误,文件描述符为2*/

参考资料:

1.教材《深入理解计算机系统》

2.博客每周测试解析

3.小组同学提问与老师的解析

4.20135202闫佳歆http://www.cnblogs.com/20135202yjx/p/4926597.html open函数部分、流部分以及代码批注

5.I/O的百度百科

 

感想

  这章书比起之前的页码少了很多,花费的时间也有所减少,大致过了一遍本以为6个小时应该差不多,结果细读下来发现还是有很多地方看不懂,然后一点一点百度下来时间就这样超出预计了。很感谢闫佳歆同学,虽然他这周的博客发得有点晚,但是十分的详细,看了他对代码的批注,对我的理解起了极大的帮助,但内容太多感觉还是没有化为自己的东西,希望老师上课能稍稍梳理一下。

 

posted on 2015-11-08 12:10  20135231  阅读(184)  评论(0编辑  收藏  举报