系统级I/O
输入/输出(I/O)是在内存和外部设备之间复制数据的过程。输入操作是从I/O设备复制数据到主存,而输出操作是从主存复制数据到I/O设备。
Unix I/O
一个Unix文件就是一个m个字节的序列:B0,B1,B(k),B(m-1),所有的I/O设备,如网络、磁盘和终端,都被模型化为文件,而所有的输入和输出都被当做对相应的文件的读和写来执行。这种将设备优雅的映射为文件的方式,允许Unix内核引出一个简单的、低级的应用接口,称为Unix I/O
- 打开文件。一个应用程序通过要求内核打开相应的文件,来宣告它想要访问一个I/O设备。内核返回一个小的非负整数,叫做描述符,它在后续对此文件的所有操作中标示这个文件。
- Linux shell创建的每个进程开始时都有三个打开的文件:标准输入(描述符为0)、标准输出(描述符为1)和标准错误(描述符为2)。头文件<unistd.h>定义了常量STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO,可用来代替显式的描述符值
- 改变当前文件的文件位置。对于每个打开的文件,内核保持着一个文件位置k,初始为0.这个文件位置是从文件开头起始的字节偏移量。
- 读写文件:一个读操作就是从文件拷贝n>0个字节到存储器。写操作就是从存储器拷贝n>0个字节到一个文件。
- 关闭文件:当应用完成了对文件的访问之后,它就通知内核关闭这个文件。作为响应,内核释放文件打开时创建的数据结构,并将这个描述符恢复到可用的描述符池中。无论一个进程因为何种原因终止时,内核都会关闭所有打开的文件并释放它们的存储器资源。
文件
打开或关闭文件
进程是通过调用open函数来打开一个已存在的文件或者创建一个新文件的
open函数将filename转换为一个文件描述符,并且返回描述符数字。返回的描述符总是在晋城中当前没有打开的最小描述符。flags参数指明了进程打算如何访问这个文件:
O_RDONLY:只读
O_WRONLY:只写
O_RDWR:可读可写
fd = open("foo.txt",O_RDONLY,0);
1
flags参数也可以是一个或者更多位掩码的或,为写提供给一些额外的指示:
O_CREAT:如果文件不存在,就创建它的一个截断的(空)文件
O_TRUNC:如果文件已经存在,就截断它
O_APPEND:在每次写操作前,设置文件位置到文件的结尾处
fd = open("foo.txt",O_ WRONLY | O_APPEND,0)
打开一个已存在的文件,并在后面添加一些数据
1
2
mode参数指定了新文件的访问权限位,当进程通过带某个mode参数的open函数调用来创建一个文件时,文件的访问权限位被设置为mode &(~umask) 。给定下面的mode和umask默认值
#define DEF_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
#define DEF_UMASK S_IWGRP|S_IWOTH
1
2
创建一个新文件,文件的拥有者有读写权限,而所有其他的用户都有读权限
umask(DEF_UMASK);
fd = open("foo.txt",O_CREAT|O_TRUNC|O_WRONLY);
1
2
最后,进程通过调用close函数关闭一个打开的文件
#include <unistd.h>
int close(int fd);
读和写文件
应用程序是通过分别调用read和write函数来执行输入和输出的
I/O重定向
LInux shell提供了I/O重定向操作符,允许用户将磁盘文件和标准输入输出联系起来
unix > ls > foo.txt
I/O重定向一种方式是使用dup2函数。
#include <unistd.h>
int dup2(int oldfd,int new fd);
返回:若成功则为非负的描述符,若出错则为-1
课上知识点
man -k key1 | grep key2| grep 2 : 根据关键字检索系统调用
grep -nr XXX /usr/include :查找宏定义,类型定义
od命令 $ od -tc -tx1 abc.txt
echo -ne "/x7b" > abc.bin 创建二进制文件