标签:sdi file 继承 键盘 时间 读取文件 也有 start 通信机制
一、知识点梳理
(一)系统级I/O概述
1.输入输出I/O
输入输出I/O是在主存和外部设备(如磁盘,网络和终端)之间拷贝数据的过程。
- 输入就是从I/O设备拷贝数据到贮存
- 输出就是从主存拷贝数据到I/O设备
2.使用原因
(二)Unix I/O
一个Unix文件就是一个m个字节的序列:B0,B1,...,Bk,...,B(m-1)
1.打开文件
- 标准错误(描述符为2)
可以用来代替显式的描述符
2.改变当前的文件位置。
3.读写文件
给定一个大小为m字节的文件,k >= m 时执行读操作会触发一个称为end-of-file(EOF)的条件,应用程序能检测到这个条件,但是文件结尾处并没有明确的“EOF符号”。
4.关闭文件
(三)打开和关闭文件
1.打开文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int open(char *filename,int fliags,mod_it mode);
- 若成功,返回值为新文件描述符
- 若出错,返回值为-1
fd = Open("文件名",flag参数,mode参数)
- O_APPEND:在每次写操作前,设置文件位置到文件的结尾处。
#define DEF_UMASK S_IWGRP|S_IWOTH
2.关闭文件:
#include<unistd.h>
int close(int fd);
3.访问权限位在sys/stat.h中定义
(四)读和写文件
1.读函数
#include<unistd.h>
ssize_t read(int fd,void *buf,size_t n);
- 若成功,返回读字节数,即实际传送的字节数量
- 若EOF,返回0
- 若出错,返回-1
注:何为EOF
即给定了m字节大小的文件,在从k字节位置开始读或者写的时候,发现k>=m。
2.写函数
#include<unistd.h>
ssize_t write(int fd,const void *buf,size_t n);
- 若成功,返回写的字节数
- 若出错,返回-1
注:ssziet,sizet的区别
- ssziet被定义为int,有符号
- sizet被定义成unsigned int,无符号
3.不足值
- 读和写网络套接字。若打开的文件对应于网络套接字,内部缓冲约束和较长的网络延迟会引起read和write返回不足值。(进程间的通信机制:对Unix管道调用read和write时,也有可能出现不足值)
(五)用RIO包健壮地读写
RIO包会自动处理不足值。RIO提供了两类不同的函数:
- 无缓冲的输入输出函数。这些函数直接在存储器和文件之间传送数据,没有应用级缓冲,对将二进制数据读写到网络和从网络读写二进制数据尤其有用。
- 带缓冲的输入函数。这些函数允许高效地从文件中读取文本行和二进制数据(函数从内部缓冲区中拷贝一个文本行,当缓冲区变空的时候,会自动地调用read重新填满缓冲区),这些文件的内容缓存在应用级缓冲区内,类似于像printf这样的标准I/O函数提供的缓冲区。带缓冲的RIO输入函数是线程安全的,它在同一个描述符上可以被交错地调用。
1.RIO的无缓冲的输入输出函数
ssize_t rio_writen(int fd,void *usrbuf,size_t n);
2.RIO的带缓冲的输入函数
rioreadinitb(riot *rp,int fd);
- 每打开一个描述符都会调用一次该函数,它将描述符fd和地址rp处的类型为rio_t的缓冲区联系起来。
rioreadnb(riot *rp,void *usrbuf,size_t n) ;
- 从文件rp中最多读n个字节到存储器位置usrbuf。对同一描述符,rioreadnb和rioreadlineb的调用可以交叉进行。
ssizet readlineb(riot *rp,void *usrbuf,size_t maxlen);
- 从文件rp中读取一个文本行(包括结尾的换行符),将它拷贝到存储器位置usrbuf,并用空字符来结束这个文本行。
3.RIO读程序的核心——rio_read函数
static ssize_t rio_read(rio_t *rp,char *usrbuf,size_t n)
{
int cnt;
while(rp->rio_cnt<=0)//如果缓冲区为空,先调用函数填满缓冲区再读数据
{
rp->rio_cnt=read(rp->rio_fd,rp->rio_buf,sizeof(rp->rio_buf));//调用read函数填满缓冲区
if(rp->rio_cnt<0)//排除文件读不出数据的情况
{
if(error != EINTR)
{
return -1;
}
}
else if(rp->rio_cnt=0)
return 0;
else
rp->rio_bufptr = rp->rio_buf;//更新现在读到的位置
}
cnt=n;
if(rp->rio_cnt<n)
cnt=rp->rio_cnt;//以上三步,将n与rp->rio_cnt中较小的值赋给cnt
memcpy(usrbuf,rp->rio_bufptr,cnt);把读缓冲区的内容拷贝到用户缓冲区
rp->rio_bufptr+=cnt;
rp->rio_cnt-=cnt;
return cnt;
}
(六)读取文件元数据
1.元数据
- fstat函数以文件描述符作为输入
2.stat数据结构
- st_size成员包含了文件的字节数大小
- st_mode成员编码了文件访问许可位和文件类型
宏指令:S_ISSOCK() 网络套接字?通过网络和其他进程通信的文件
(七)共享文件
1.内核表示打开文件的三个相关的数据结构
- 描述符表:每个打开的描述符表项指向文件表中的一个表项
- 文件表:所有进程共享这张表,每个表项包括文件位置,引用计数,以及一个指向v-node表对应表项的指针
- v-node表:所有进程共享这张表,包含stat结构中的大多数信息
(1)典型的打开文件的内核数据结构
- 描述符1~4通过不同的打开文件表表项来引用两个不同的文件。
(2)文件共享
、
- 两个描述符通过打开两个打开文件表表项共享同一个磁盘文件。
- 关键思想:每个描述符都有自己的文件位置,对不同描述符的读操作可以从文件的不同位置获取数据
(3)父子进程共享文件
- 调用fork后,子进程有一个父进程描述符表的副本。
- 父子进程共享相同的打开文件表集合,因此共享相同的文件位置。
- 在内核删除相应文件表表项之前,父子进程必须都关闭了他们的描述符
(八)I/0重定向
int dup2(int oldfd,int newfd);
(九)标准I/O和I/O函数
extern FILE *stderr; //标准错误,描述符2
标签:sdi file 继承 键盘 时间 读取文件 也有 start 通信机制
原文地址:http://www.cnblogs.com/20145207lza/p/6052573.html