第十章的内容为p657~p675.
摘要
Unix将所有I/O抽象为文件, 将所有输入/输出操作抽象为read/write. 最底层的方法为Unix I/O, 之上为了提高效率避免多次调用Unix I/O, 以及处理不足值的清空, 出了有带缓冲区健壮的RIO,
还有之上更加完善的C的标准I/O.
Unix I/O
- 打开文件, 返回一个描述符
- 默认3个打开的文件, StdIn, StdOut, StdErr.
- Seek, 改变当前位置
- Read/Write
- Close
文件类型
- 普通文件, 分文本文件和二进制文件
- 目录, 是包含一组链接的文件, 每个链接都将一个文件名链接到文件, 每个目录至少包含2个条目, "."和"..", 分别链接自己和父目录
- 套接字, 是用来与另一个进程进行跨网络通信的文件
打开和关闭文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcnt1.h>
int open(char *filename, int flags, mode_t mode); //若成功返回新文件描述符, 出错返回 -1
flags有几种类型, O_RDONLY(只读), O_WRONLY(只写), O_RDWR(可读写), O_CREAT(创建新文件), O_TRUNC(清空文件), O_APPEND(写内容到文件结尾)
mode有几种类型, S_IRUSR(所有者拥有读权限), S_IWGRP(群组拥有写权限), S_IXOTH(其他用户拥有执行权限). 模式S_I [RWX] [USR|GRP|OTH].
#include <unistd.h>
int close(int fd);
读写文件
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t n); //成功返回读的字节数, EOF则为0, 错误为-1
ssize_t write(int fd, const void *buf, size_t n); //成功返回写的字节数, 错位为-1
RIO包
#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);
相比Unix I/O, RIO有2个优点, 1是带缓冲区, 避免过于频繁的调用Unix I/O接口; 2是处理好了不足值的情况, 尤其是处理网络程序.
读取文件元数据
#include <unistd.h>
#include <sys/stat.h>
int stat(const char * filename, struct stat *buf);
int fstat(int fd, struct stat *buf);
这个方法只存在Unix I/O, 不存在于RIO和标准I/O.
S_ISREG(是否普通文件), S_ISDIR(是否目录文件), S_ISSOCK(是否网络套接字).
读取目录
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name); //成功返回处理的指针, 错误返回NULL
struct dirent *readdir(DIR *dirp); //读取目录下的所有文件.
int closedir(DIR *dirp);//成功为0, 错误-1.
共享文件
- 描述符表. 每个进程独享一个描述符表, 每一个Item指向file table的一个item.
- File Table. 打开文件的集合由一个File Table表示, 所有进程共享一个表, 每个Item由当前的文件位置, 引用计数, 以及一个指向v-node表item的指针. 关闭一个描述符会减少相应File Table的item的引用计数, 直到引用计数为0, 系统才会删除这个File table item.
- V-node表. 所有进程共享. 每个item包含文件的stat信息.
I/O重定向
#include <unistd.h>
int dup2(int oldfd, int newfd); //成功返回非负描述符, 错误返回-1.
标准I/O
C语言定义的高级函数库, 提供了
- 打开关闭函数fopen 和 fclose
- 读写字节的函数fread 和 fwrite
- 读写字符串的函数fgets 和 fputs
- 格式化函数 scanf 和 printf
总结
- 尽可能使用标准I/O, 除stat外, 标准I/O没有对应的函数
- 不要使用scanf或rio_readlineb来读二进制文件, 而是用来读文本文件
- 对网络套接字使用RIO