系统级IO
系统级IO
输入:IO设备复制数据到主存
输出:主存复制数据到IO设备
Unix I/O
标准 I/O
Unix IO
所有的IO设备(例如网络、磁盘、终端)都被模型化为文件,所有输入输出都能被当作相应文件的读写来执行。
这种将设备优雅地映射到文件的方式,得到一个简单、低级的应用接口,称为 Unix I/O
- 打开文件
- 本质:宣告它要访问一个I/O设备,内核返回一个小的非负整数 —— 描述符。应用程序只需记住这个描述符
- 默认打开的文件:Linux Shell 创建的每个进程开始时都有三个打开的文件:标准输入 (描述符0)、标准输出 (描述符1)、标准错误 (描述符2)
- 改变当前文件的位置 (指读写位置)
- 概念:对于每个打开的文件,内核保持着一个文件位置k,初始为0。是从文件开头的字节偏移量。
- 修改:应用程序能通过
seek
操作,设置文件的当前位置
- 读写文件
- 读操作:就是从文件中复制n>0字节到内存,然后k=k+n
- 写操作:同理。注意往m大小文件读k时,会触发 end-of-file (EOF)
- 关闭文件
- 本质:通知内核关闭这个文件(或程序终止)。内核会将该描述符恢复到可用的描述符池中
文件
每个Linux文件都有一个类型 (type)
普通文件 (regular file):
- 文本文件 (text file):只含有ASCII或U你错de字符的普通文件(Linux文本文件换行符是LF、0x0a)
- 二进制文件 (binary file):文本文件以外的所有文件
目录 (directory)
包含一组链接 (link) 的文件,每个链接都将一个文件名 (filename) 映射到一个文件,这个文件可能是另一个目录
特殊:“.” 是到该目录自身的链接,“..” 是到目录层次结构中父目录的链接。相关指令:mkdir、ls、rmdir
套结字 (socket)
- 用来和另一个进程进行跨网络通信的文件
每个进程都有一个 当前工作目录 (current working directory, cwd, 不同于启动位置ed),用来确定其在目录层次结构中的当前位置
- 绝对路径名 (absolute pathname)
- 相对路径名 (relative pathname)
打开和关闭文件
open
open函数打开或创建一个新的文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/**
* 打开文件,将filename转换为一个文件描述符,并返回描述符数字
* @param filename 文件名
* @param flags (可用与逻辑叠加)
* 控制1
* O_RDONLY:只读
* O_WRONLY:只写
* O_RDWR:读写
* 控制2
* O_CREAT:不存在则创建
* O_TRUNC:存在则截断
* O_APPEND:每次写操作前,设置文件内位置到文件结尾
* @return 成功则文件描述符,出错-1
*/
int open(char* filename, int flags, mode_t mode);
// 使用举例
fd = Open("foo.txt", O_WRONLY|O_APPEND, 0)
创建有访问权限的文件
访问权限位(sys/stat.h中定义):略
掩码 | 描述 |
---|---|
close
#include <unistd.h>
/**
* @return 成功0,出错-1
*/
int close(int fd);
读和写文件
read、write
#include <unistd.h>
/**
* @return 成功返回读的字节数,EOF则0,出错-1
*/
ssize_t read(int fd, void* buf, size_t n);
/**
* @return 成功返回成功写的字节数,出错-1
*/
ssize_t write(int fd, const void* buf, size_t n);
lseek
能修改当前的文件内位置
用RIO包健壮地读写
RIO (Robust I/O,健壮的I/O包)
提供了两类不同的函数:
- RIO的无缓存的输入输出函数
- RIO的带缓存的输入函数
RIO的无缓存的输入输出函数
RIO的带缓存的输入函数
读取文件元数据
读取目录内容
共享文件
IO重定向
标准IO
综合:我该使用哪些IO函数?
小结
链接到当前文件 0
没有文件链接到当前文件