• 20135333苏正生——信息安全系统设计基础第八周学习总结


    第十章 系统级I/O

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

    第一节 Unix I/O

    1.打开文件:
    应用程序向内核发出请求→要求内核打开相应的文件→内核返回文件描述符
    文件描述符:
    标准输入——0(STDIN_FILENO)
    标准输出——1(STDOUT_FILENO)
    标准错误——2(STDERR_FILENO)
    括号中是常量表示形式,使用时需要加头文件
    二者的主要区别为:
    数据类型不同,前者为int类型,后者为FILE
    *STDIN_FILENO主要用在read(),write()等中,后者主要用在fread(),fwrite()以f开头。
    2.改变当前的文件位置
    通常,读,写操作都从当前文件偏移量处开始(也就是文件位置),并使偏移量增加所读写的字节数,可以理解为光标所在的位置。
    3.读写文件
    (1)读
    读操作就是从文件拷贝n>0个字节到存储器,并且改变文件当前位置。
    (2)写
    写操作是从存储器拷贝n>0个字节到一个文件,然后更新当前文件位置。
    4.关闭文件
    应用通知内核关闭文件→内核释放文件打开时的数据结构→恢复描述符→释放存储器资源。

    第二节 打开和关闭文件

    1.open函数
    (1)函数定义:
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    int open(char *filename, int flags, mode_t mode);
    (2)参数解析:
    返回值:类型为int型,返回的是描述符数字,总是在进程中当前没有打开的最小描述符。如果出错,返回值为-1.
    filename:文件名
    flags:指明进程打算如何访问这个文件,可以取的值见下:
    O_RDONLY:只读
    O_WRONLY:只写
    O_RDWR:可读可写
    O_CREAT:文件不存在,就创建新文件
    O_TRUNC:如果文件存在,就截断它
    O_APPEND:写操作前设置文件位置到结尾处
    mode:指定了新文件的访问权限位
    2.close函数
    (1)函数定义:
    #include <unistd.h>
    int close(int fd);
    (2)参数解析:
    返回值:成功返回0,出错返回-1
    关闭一个已经关闭的描述符会出错
    fd:即文件的描述符。

    第三节 读和写文件

    1.读 read
    (1)函数原型:
    #include <unistd.h>
    ssize_t read(int fd, void *buf, size_t n);
    (2)参数解析:
    返回值:成功则返回读的字节数,EOF返回0,出错返回-1。返回值为有符号数。
    fd:文件描述符
    buf:存储器位置
    n:最多从当前文件位置拷贝n个字节到存储器位置buf
    2.写 write
    (1)函数原型:

    #include <unistd.h>
    ssize_t write(int fd, void *buf, size_t n);
    

    (2)参数解析:
    返回值:成功则返回写的字节数,出错返回-1。返回值为有符号数。
    fd:文件描述符
    buf:存储器位置
    n:最多从存储器位置buf拷贝n个字节到当前文件位置
    3.通过lseek函数可以显式的修改当前文件的位置
    读和写socket

    第四节 用RIO包健壮的读写

    RIO,Robust 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);
    

    参数:
    fd:文件描述符
    usrbuf:存储器位置
    n:传送的字节数
    返回值:
    rio_readn成功则返回传送的字节数,EOF为0(一个不足值),出错为-1
    rio_writen成功则返回传送的字节数,出错为-1,没有不足值。
    2.RIO的带缓冲的输入函数
    可以高效的从文件中读取文本行和二进制数据。
    一个概念:一个文本行就是一个由换行符结尾的ASCII码字符序列。
    范例:如何统计文本文件中文本行的数量——通过计算换行符。需要用到的函数:

    #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);
    

    【课本代码】
    图10-4:

    #include "csapp.h"
    int main(int argc, char **argv) 
    {
       int n;
       rio_t rio;
       char buf[MAXLINE];
       Rio_readinitb(&rio, STDIN_FILENO);
       while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0)
       Rio_writen(STDOUT_FILENO, buf, n);
       exit(0);
    }
    

    图10-5:

    #define RIO_BUFSIZE 8192
    typedef struct {
       int rio_fd;                /* descriptor for this internal buf */
       int rio_cnt;               /* unread bytes in internal buf */
       char *rio_bufptr;          /* next unread byte in internal buf */
       char rio_buf[RIO_BUFSIZE]; /* internal buffer */
    } rio_t;
    void rio_readinitb(rio_t *rp, int fd) 
    {
       rp->rio_fd = fd;  
       rp->rio_cnt = 0;  
       rp->rio_bufptr = rp->rio_buf;
     }
    

    图10-6:

    static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n)
    {
       int cnt;
       while (rp->rio_cnt <= 0) {  /* 如果缓存区为空,调用read填满它 */
       rp->rio_cnt = read(rp->rio_fd, rp->rio_buf, 
    		   sizeof(rp->rio_buf));
       if (rp->rio_cnt < 0) {
           if (errno != EINTR) /* 出错返回-1*/
    	return -1;
       }
       else if (rp->rio_cnt == 0)  /* EOF返回0 */
           return 0;
       else 
           rp->rio_bufptr = rp->rio_buf; /* reset buffer ptr */
       }
       cnt = n;          
       if (rp->rio_cnt < n)   
       cnt = rp->rio_cnt;
       memcpy(usrbuf, rp->rio_bufptr, cnt);
       rp->rio_bufptr += cnt;
       rp->rio_cnt -= cnt;
       return cnt;
    }
    

    rio_readnb函数

    ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n) 
    {
       size_t nleft = n;
       ssize_t nread;
       char *bufp = usrbuf;
       while (nleft > 0) {
       if ((nread = rio_read(rp, bufp, nleft)) < 0) {
           if (errno == EINTR) 
    	   nread = 0; 
           else
    	   return -1;
       } 
       else if (nread == 0)
           break;
       nleft -= nread;
       bufp += nread;
       }
       return (n - nleft);
    }
    

    rio_readlineb函数

    ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen) 
    {
     int n, rc;
     char c, *bufp = usrbuf;
    
     for (n = 1; n < maxlen; n++) {
    if ((rc = rio_read(rp, &c, 1)) == 1) {
        *bufp++ = c;
        if (c == '
    ')
    	break;
    } else if (rc == 0) {
        if (n == 1)
    	return 0;
        else
    	break;
    } else
        return -1;
     }
     *bufp = 0;
     return n;
    }
    

    第五节 读取文件元数据

    元数据即文件信息,需要用到的函数是stat和fstat。定义如下:

    include <unistd.h>

    include <sys/stat.h>

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

    普通文件 二进制或文本文件(对内核没差) S_ISREG()
    目录文件 关于其他文件的信息 S_ISDIR()
    套接字 通过网络与其他进程通信的文件 S_ISSOCK()
    查询和处理一个文件的st_mode位:

    #include "csapp.h"
    int main (int argc, char **argv) 
    {
       struct stat stat;
       char *type, *readok;
    
       Stat(argv[1], &stat);//文件选择argv[1],写入一个stat数据结构
       if (S_ISREG(stat.st_mode))     /* 如果是一个文本文件 */
    type = "regular";
       else if (S_ISDIR(stat.st_mode))//如果是一个目录文件
    type = "directory";
       else 
       type = "other";
       f ((stat.st_mode & S_IRUSR)) /* 检查阅读权限 */
    readok = "yes";
     else
    readok = "no";
    
     printf("type: %s, read: %s
    ", type, readok);
     exit(0);
    }
    

    第六节 共享文件

    内核用三个相关的数据结构来表示打开的文件:
    描述符表
    文件表:打开文件的集合是由一张文件表来表示的。
    v-node表

    第七节 I/O重定向

    I/O重定向操作符: >
    ls > foo.txt
    这句代码的含义就是使外壳加载和执行ls程序,并且将标准输出重定向到磁盘文件foo.txt。
    I/O重定向函数: dup2
    函数定义为:

    #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.流——类型为FILE的流是对文件描述符和流缓冲区的抽象

    参考资料:
    1.《深入理解计算机系统》
    2.Linux系统编程学习笔记(三)高级文件I/O - fuliang - ITeye技术网站
    http://fuliang.iteye.com/blog/652297
    心得体会:
    本周课程在书本中仅仅有十页,但是内容却远远的超过十页,不仅要看书本内容,还要代码,理解每行的意思,熟悉代码中调用i/o的过程。 通过本周的学习,对于之前的存储器,链接,以及计算机操作系统中的进程调度都有了更深的了解。

  • 相关阅读:
    HDUoj(1002)A + B Problem II
    HIT Summer 20180731
    Windows10下python3.5对维基百科语料用word2vec进行训练寻找同义词相似度
    关键词抽取
    win10+python遇到:Using TensorFlow backend.错误
    Windows下Python3.5+numpy+keras+tesorflow的环境配置
    常用的一些序列号
    Umbraco扩展开发
    Umbraco Content属性
    Windows查看端口占用
  • 原文地址:https://www.cnblogs.com/suzhengsheng/p/4948588.html
Copyright © 2020-2023  润新知