教材学习内容总结
Unix I/O
输入/输出 是在主存和外部设备之间拷贝数据的过程 一个Unix文件就是一个m字节的序列:B0、B1、、、Bk、、、Bm-1,如网络、磁盘、终端,都被模式化为文件,所有的输入输出都被当作对相应文件的读和写来执行。
打开文件:
内核返回描述符,以标识文件。内核记录有关打开文件的所有信息。unix创建每个进程都有:标准输入、标准输出、标准错误 改变当前的文件位置:这个文件位置是从文件开头起始的字节偏移量 读写文件 关闭文件
打开、关闭文件
int open(char*filename, int flags,mode_t mode); open 函数将filename转换为一个文件描述符,并且返回描述符数字 flags参数指明进程打算如何访问 mode参数指定新文件的访问权限
int close(int fd);
进程通过调用close函数关闭一个打开的文件,关闭一个已关闭的描述符会出错
读和写文件
应用程序是通过分别调用read和write函数来执行输入和输出。 RIO,会自动处理上文中所述的不足值。提供了无缓冲的输入输出函数和带缓冲的输入函数
RIO无缓冲的输入输出函数:调用rioreadn和riowriten
RIO带缓冲的输入函数:rio_readlineb,从一个内部读缓冲区拷贝一个文本行
每打开一个描述符都会调用一次rioreadinitb函数,它将描述符fd和地址rp处的一个类型为riot的读缓冲区联系起来 对同一描述符,对rio_readlineb和rioreadnb的调用可以任意交叉进行。然而对这些带缓冲的函数调用却不应和无缓冲的rioreadn交叉使用
读取文件元数据
应用程序能够通过调用stat和fstat函数,检索到关于文件的元数据 stat以文件名作为输入。fstat以文件描述作为输入 stsize成员 包括文件的字节数大小。stmode成员编码了文件的访问许可位和文件类型 普通文件包括某种类型的二进制或文本数据 目标文件包含关于其他文件的信息 套接字是一种用来通过网络与其他进程通信的文件
Unix提供的宏指令根据st_mode成员来确定文件的类型
宏指令:SISREG() 普通文件?二进制或文本数据 宏指令:SISDIR() 目录文件?包含其他文件的信息 宏指令:S_ISSOCK() 网络套接字?通过网络和其他进程通信的文件
教材学习中的问题和解决过程
man -k key1 | grep key2| grep 2 : 根据关键字检索系统调用 grep -nr XXX /usr/include :查找宏定义,类型定义 man cp
在帮助文档中,通过/+关键词查找,向后查找:n,向前:N
grep -r递归查找-v反向查找
标准I/O库将一个打开的文件模型化为一个流。一个流就是一个指向FILE类型的结构的指针。每个ANSI C程序开始时都有三个打开的流:
include<stdio.h> extern FILE stdin; //标准输入,描述符0 extern FILE stdout; //标准输出,描述符1 extern FILE *stderr; //标准错误,描述符2```
类型为FILE的流是对文件描述符和流缓存区的抽象。流缓冲区的目的和RIO读缓冲区的一样,就是使开销较高的UnixI/O系统调用的数量尽可能的少。 各类I/O关系
Unix I/O是在操作系统内核中实现的。
较高级别的RIO和标准I/O函数都是基于Unix函数来实现的。 RIO函数是专为本书开发的read和write的健壮的包装函数。他们自动处理不足值,并且为读文本行提供一种高效的带缓冲的方法 标准I/O函数提供了Unix函数的一个更加完整的带缓冲的替代品,包括格式化的I/O例程。 标准I/O流,从某种意义上是全双工的,但对流的限制和对套接字的限制有时会相互冲突。 限制一:跟在输出函数之后的输入函数 限制二:分在输入函数的输出函数 由此,建议在网络套接字上不要使用标准 I/O函数来进行输入和输出,而要使用健壮的RIO函数。
问题解决
1.flags参数:
O_TRUNC:如果文件已经存在,就截断它。 如何理解截断?
在c++中ios:
:trunc与ios::out的效果应该是一样的,也就是打开文件的时候先将文件的内容清空,再进行写入。并不是删除文件。 截断后文件就是空文件了,所有文件指针可以说在最前面也是最后面。截断后文件还是那个文件(如果文件存在的话),但是内容没有了。 类比可知,O_TRUNC : 如果文件已存在,就截断它(长度被截为0,属性不变) 2.练习题10.1 代码输入后编译显示找不到csapp.h
解决:
通过搜索得知csapp.h是一堆头文件的打包,在http://csapp.cs.cmu.edu/public/code.html 这里可以下载,linux应该没有自带csapp.h。于是更改了头文件,编译成功。