基础I/O
I/O:input和output
1.C文件接口及标准输入、输出和错误
fopen、fclose
FILE* fopen(const char * filename, const char * mode)
作用:以mode方式打开一个名为filename的文件
参数:filename文件名;mode文件的打开方式
返回值:文件流指针
int fclose(FILE* stream);
作用:关闭一个打开的文件
参数:要关闭的文件的流指针
返回值:成功返回0,失败返回-1
const char * mode的形式
文件使用方式 | 含义 | 如果指定文件不存在 |
“r”(只读) | 为了输入数据,打开一个已经存在的文本文件 | 出错 |
“w”(只写) | 为了输出数据,打开一个文本文件 | 建立一个新的文件 |
“a”(追加) | 向文本文件尾添加数据 | 建立一个新的文件 |
“rb”(只读) | 为了输入数据,打开一个二进制文件 | 出错 |
“wb”(只写) | 为了输出数据,打开一个二进制文件 | 建立一个新的文件 |
“ab”(追加) | 向一个二进制文件尾添加数据 | 出错 |
“r+”(读写) | 为了读和写,打开一个文本文件 | 出错 |
“w+”(读写) | 为了读和写,建议一个新的文件 | 建立一个新的文件 |
“a+”(读写) | 打开一个文件,在文件尾进行读写 | 建立一个新的文件 |
“rb+”(读写 | 为了读和写打开一个二进制文件 | 出错 |
“wb+”(读写) | 为了读和写,新建一个新的二进制文件 | 建立一个新的文件 |
“ab+”(读写) | 打开一个二进制文件,在文件尾进行读和写 | 建立一个新的文件 |
读、写文件:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
作用:读取文件中的内容
参数:ptr读出的内容;size一次读取的长度;nmemb读取的次数;stream读取的文件流指针
返回值:成功读取的字节数,如读取失败返回0
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
作用:写入文件中的内容
参数:ptr写入的内容;size一次写入的长度;nmemb写入的次数;stream写入的文件流指针
返回值:成功写入的字节数,如读取失败返回0
标准输入、标准输出和标准错误:
- C默认会打开三个输入输出流,分别是stdin, stdout, stderr
- 仔细观察发现,这三个流的类型都是FILE*, fopen返回值类型,文件指针
2.系统调用I/O
open()函数:打开或创建一个文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char* pathname,int flags);
int open(const char* pathname,int flags,mode_t mode);
- pathname:要打开或创建的文件名(包含目录,可以是相对路径也可以是绝对路径)
- flags:
必选项,以下三个中必须选定一个,且仅允许指定一个
O_RDONLY:以只读方式打开文件
O_WRONLY:以只写方式打开文件
O_RDWR:以可读写方式打开文件
下列的可用按位或(|)运算符连接起来:
O_CREAT:若此文件不存在则创建它
O_TRUNC:如果文件已存在,若文件存在,则长度被截为0,属性不变
O_APPEND:如果文件已有内容,这次打开文件所写的数据附加到文件的末尾而不覆盖原来的内容。 - mode:设置文件的访问权限,可以直接给八进制的文件权限位(一般给0644),使用时还需考虑掩码
- 返回值:
成功:返回新分配的文件描述符
失败:返回-1
由open返回的文件描述符一定是该进程尚未使用的最小描述符。
write:
write():向打开的设备或文件中写数据
#include <unistd.h>
ssize_t write(int fd,const void* buf,size_t count);
作用:向文件中写入内容
参数:fd文件描述符;buf写入的字符串;count写入的大小
返回值:成功返回写入成功的字节数,失败返回-1
read:
read()函数:从打开的设备或文件中读取数据
ssize_t read(int fd, void *buf, size_t count);
作用:从文件中读取内容
参数:fd文件描述符;buf输出型参数,保存读出的内容;count读取的大小
返回值:成功返回读取成功的字节数,失败返回-1
close:
close()函数:关闭一个已打开的文件
#include <unistd.h>
int close(int fd);
参数:要关闭的文件的文件描述符
返回值:成功返回0,失败返回-1
3.文件描述符
Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2
文件描述符就是从0开始的正整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件,于是就有了file结构体,用来表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个结构体指针files, 指向一个files_struct结构体,该结构体最重要的部分就是包含一个指针数组,每个元素都是struct file结构体一个指向打开文件的指针。所以本质上,文件描述符就是该数组的下标。只要拿着文件描述符,就可以找到对应的文件 。
文件描述符的分配规则:在file_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。
dup2系统接口重定向
重定向将一个文件描述符所对应fd_array数组当中的元素所指的struct file*的内容更改为另外一个文件信息,意味着当前文件描述符所对应的struct file指向的文件被另外一个文件替代了。
1. > 清空重定向,清空文件之间的内容,在重定向到文件中
2. >> 追加重定向,追加在文件之后
3. < 输出重定向
缓冲区
我们的缓冲区是由语言提供的,由FILE 结构体进行维护。
- 一般C库函数写入文件是全缓冲的,而写入显示器是行缓冲。
- printf fwrite 库函数是用户级的缓冲区,当发生重定向到普通文件的时候,数据的缓冲方式就由行缓冲变成了全缓冲。
dup2系统接口
#include <unistd.h>
int dup2(int oldfd,int newfd);
newfd是oldfd的一份拷贝。newfd复制参数oldfd所指的文件描述符,并将它返回。此新的文件描述符和参数oldfd所指的是同一个文件,共享所有的锁定、读写位置和各项权限。