C中的I/O操作
标准库IO接口
fopen 打开文件
FILE* fopen(const char* path,const char* mode);
fwrite 向文件写入数据
FILE* fwrite(const void* ptr,size_t size,size_t nmemb,FILE* stream);
ptr:要写入的数据
size:要写入的数据块大小
nmemb:要写入的数据块个数
stream:文件流指针
fread 从文件读取数据
size_t fread(void* ptr,size_t size,size_t nmemb,FILE* stream);
fssek 从文件读取数据
int fssek(FILE* stream,long offset,int whence);
stream 文件流指针
offset 偏移量
whence 偏移起始位置
fclose 关闭文件
int fclose(FLIE* fp);
需要注意 fwrite fread 的返回值是 size_t 类型;
对文件中的数据进行处理的时候,使用字符串处理函数有可能会出现未知的问题,因为文件中可能有空数据,字符串处理函数遇到空字符则认为字符串结束,导致文件数据并未完全处理。
系统文件I/O
系统调用接口
open 打开文件
int open(const char* pathname,int flags,mode_t mode);
pathname:文件名
falgs:选项标志 O_RDONLY(只读打开) / O_WRONLY(只写打开) / O_RDWR(读,写打开)
mode:文件权限
write 文件写入
ssize_t write(int fd,const void* buf,size_t count);
fd:打开文件返回的操作句柄——文件描述符
buf:要写入的数据
count:要写入的数据长度
read 从文件读数据
ssize_t read(int fd,void* buf,size_t count);
fd:打开文件返回的操作句柄——文件描述符
buf:读到的数据放到 buf 中
count:要读取的数据长度
lseek 跳转读写位置
off_t lseek(int fd,off_t offset,int whence);
fd:打开文件返回的操作句柄——文件描述符
offset:偏移量
whence:偏移起始位置 SEEK_SET(文件起始位置) / SEEK_CUR(当前读写位置) / SEEK_END(文件末尾位置)
close 关闭文件
int close(int fd);
系统调用接口 和 库函数:可以认为 f# 系列的函数,都是对系统调用的封装,方便二次开发。
文件流流指针(FLIE*)和 文件描述符(int)之间的关系
文件流指针是标准库操作句柄、文件描述符是系统调用接口的句柄
除了封装的关系,还有文件流指针中包含了文件描述符这么个变量,最终起作用的是文件流指针;
缓冲区是用户态的缓冲区,存在于文件流指针结构体中;
文件描述符到底是什么?
当我们打开文件的时候,操作系统在内存中要创建相应的数据结构来描述目标文件,遇时就有了file 结构体,表示一个已经打开的文件对象,而进程指向 open 系统调用,所以必须让进程和文件关联起来,每个进程都一个指针*file,指向一张表 file_struct ,该表最重要的部分就是包含了一个指针数组,每个元素都有个指向打开文件的指针。
文件描述符是内核中的 struct file* fd_array[ ]数组的下标,这个数组中存放的就是文件描述符的信息。
文件描述符的分配规制是:在file_struct 数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。
重定向
看一段代码
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib>
int main(){
close(1);
int fd = open("myfile",O_WRONLY | O_CREAT,00644);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n",fd);
fflush(stdout);
close(fd);
return 0;
}
按照我们的预想,应该是会输出:“fd: 1”; 但是!
并没有输出,并且当前路径下还多了一个 myfile 文件,发现我们本来应该输出的结果 被写入到了 mylie 文件中;
重定向的本质
重定向:重定向的是文件描述符,改变一个文件描述符所对应的文件描述信息;
改变了文件描述符所对应的文件描述信息,对描述符写入数据,改变了数据的流向,数据从原本要写入的文件,流向了新文件。
"\n":刷新缓冲区仅仅针对的是标准输出文件,对于其他磁盘文件并不具备刷新缓冲区的作用。