目录
我们最早接触IO操作函数应该就是c语言了吧,所有今天我们从c语言中的函数出发,逐层剥离,回归到IO操作的本质。
一、库函数
1.fopen
FILE *fopen( const char*path , const char *mode); //path:需要打开文件的地址,也包括文件名,若文件在当前路径下,可直接使用文件名。 //mode:打开文件的参数,具体参数如下
r:只读模式打开 r+:可读可写模式打开 w:若文件存在,清空文件内容;若文件不存在,则创建一个新文件 a:若文件存在,就在文件原有内容后接着写;若不存在,就创建文件 a+:可读也可追加写。若文件不存在,就创建文件
返回值
成功:文件流指针
失败:NULL
2.fclose
int close(FILE *fp); //fp:文件流指针
3.fwrite
size_t fwrite(const void *buf , size_t size ,size_t nmemb,FILE *stream) //buf:写的内容 //size:定义往文件中写的时候一个块多大,单位字节。 //nmemb:期望写多少个块 //stream:文件流指针
返回值
成功写入的块的个数
4.fread
size_t fread( void *ptr , size_t size ,size_t nmemb,FILE *stream) //ptr:将文件内容读到ptr指向的内存空间中 //size:定义文件中读的时候一个块多大,单位字节。 //nmemb:期望读多少个块 //stream:文件流指针
返回值
成功写入的块的个数
5.fseek
int fseek(FILE *stream,long offset,int whence); //stream:文件流指针 //offset:偏移量 /*whence:将文件流指针偏移到什么位置 SEEK_SET:文件开头 SEEK_CUR: 当前文件流指针的位置 SEEK_END:文件末尾*/
返回值
成功:0
失败:-1
以上为c语言标准库函数,下边为系统调用函数,系统调用是操作系统提供的接口,主要是面向硬件的,库函数一般是大牛程序员将系统调用封装简化之后给其他程序员的,目的是为了方便编程。如果你想写程序,使用系统调用和库函数都是可以的。
二、系统调用
1.open
int open (const char *pathname,int flags); int open(const char *pathname,int flags,mode_t mode); /*pathname:要打开的目标文件 flags:打开文件的3个参数(有且只能有一个) O_RDONLY:只读打开 O_WRONLY:只写打开 O_RDWR:读写打开 可选参数: O_CREAT:若文件不存在,则创建 O_APPEND:追加写 mode:打开文件的权限*/
例子:
int open( buf , O_RDWR | O_CREAT , 0664);
2.close
int close(int *fd);
3.write
int write(int fd,const void *buf,size_t count); /* fd:文件描述符 buf:将buf指向的内容写到文件中去 count:期望写多少字节 */
返回值
返回写的字节数量
4.read
int read(int fd,void *buf,size_t count); /* fd:文件描述符 buf:将文件中的内容读到buf指向的内存空间中去 count:期望读多少字节 */
返回值
返回读的字节数量
5.lseek
off_t lseek(int fd,off_t offset,int whence); /* fd:文件流指针 offset:偏移量 whence:将文件流指针偏移到什么位置 SEEK_SET:文件开头 SEEK_CUR: 当前文件流指针的位置 SEEK_END:文件末尾 */
返回值
成功:返回偏移位置
失败:-1
三、文件流指针和文件描述符
此时你会发现,系统调用传参都是文件描述符,库函数封装之后就是文件流指针。
“文件流指针”是一个被称为FILE结构的数据结构,这个结构体实际上定义了一个缓冲区和一个文件描述符值。
Q:为什么库函数封装的时候要增加定义这个缓冲区?
因为IO操作太耗费时间,cpu要是阻塞等待IO操作的话,效率太低,于是人们想出一个办法,在读写时不用每个字节都进行IO操作,可以等信息积攒到一定量之后,再进行IO操作。积攒的这个过程,信息就放在缓冲区。这样就能减少IO次数,提高效率。
Q:我不使用库函数,直接使用系统调用是不是就不用经过缓冲区了?
对的,库函数才定义了缓冲区,系统调用传递的参数是文件描述符,所以是实时进行IO操作的。
Q:文件流指针具体是如何封装文件描述符的?
系统调用简单工作原理
左边的框是进程控制信息,后边的博客我会讲解,pcb中的一个成员变量是文件指针,文件指针结构体其实是一个数组,这个数组保存着这个进程打开的所有文件信息,数组的下标其实就是文件描述符。实际系统调用时其实传递的就是这个数组下标,然后就能找到对应的属于具体文件的结构体指针,通过指针指向的空间就能找到文件信息。
文件流指针原理
读写缓冲区其实就是三个指针,分别指向缓冲区开始、结束、当前读写位置,当读写指针到达缓冲区尾时,刷新缓冲区。
Q:那我自己可以指定文件和文件描述符的关系吗?
当然可以,这个时候就要使用重定向函数了,它的作用将newfd的值变为oldfd.
int dup2(int oldfd,int newfd); //newfd,oldfd都是文件描述符
成功:
关闭newfd;
newfd指向oldfd所指的结构体
失败:
保持原样
以上就是全部关于文件描述符和文件流指针的操作了,希望各位看官老爷看的开心。