Skip to content

标准IO

为什么使用标准IO?
系统IO在不同操作系统下的API接口不一致:

  • Linux: open, read, write, close...
  • Windows: winopen, winread...

C/C++语言标准委员会统一了文件操作接口 --> 标准IO

  • 支持所有操作系统
  • 提供统一的文件操作函数
  • 通过IO流(文件)抽象文件操作

文件类型

  1. 文本文件
    • 无组织、无格式,以字符ASCII解析
    • 如:.cpp, .c, .txt, .cs, .html, .java, .py...
  2. 二进制文件
    • 有特定格式,需按格式解析
    • 如:.exe, .out, .apk, .jpg, .mp4, .doc, .xls...

文件描述结构
标准库用FILE结构体描述文件,包含两个缓冲区:

  • 读缓冲区 (char *in)
  • 写缓冲区 (char *out)

操作流程
应用程序 -> 标准IO库 -> 操作系统IO -> 操作系统内核 -> 硬件

效率优势

  • 系统IO:读1字节需从硬盘取1字节
  • 标准IO:读1字节从硬盘取整块数据放入缓冲区
    • 缓冲类型
      类型同步条件默认大小
      行缓冲缓冲区满/遇到\n/程序正常退出1024字节
      全缓冲缓冲区满4096字节
      无缓冲有1字节即同步1字节

标准IO流

程序自动打开三个标准IO流:

  1. 标准输入流FILE *stdin
    • 指向输入设备(键盘)
    • 如:scanf
  2. 标准输出流FILE *stdout
    • 指向输出设备(终端)
    • 如:printf
  3. 标准出错流FILE *stderr
    • 指向错误输出设备(终端)
    • 如:perror

标准IO API接口

打开/关闭文件流

c
FILE *fopen(const char *filename, const char *modes);  
/*  
@描述:  
    打开文件流  
@filename:  
    文件名(含路径)  
@modes:  
    "r"    : 只读,流定位到文件开头  
    "r+"   : 读写,流定位到文件开头  
    "w"    : 只写,截断文件或创建新文件  
    "w+"   : 读写,文件不存在则创建,存在则截断  
    "a"    : 追加写入,文件不存在则创建  
    "a+"   : 读写追加,写入时定位到文件末尾  
@return:  
    成功返回FILE*指针,失败返回NULL(errno被设置)  
*/  

int fclose(FILE *stream);  
/*  
@描述:  
    关闭文件流  
@stream:  
    文件流指针  
@return:  
    成功返回0,失败返回EOF(errno被设置)  
*/

读写操作

单字节读写
c
// 读取单字节  
int fgetc(FILE *stream);  
/*  
@描述:  
    从文件流读取一个字符  
@stream:  
    文件流指针  
@return:  
    成功返回字符ASCII码,失败返回EOF  
*/  

// 写入单字节  
int fputc(int c, FILE *stream);  
/*  
@描述:  
    写入字符到文件流  
@c:  
    字符ASCII码  
@stream:  
    文件流指针  
@return:  
    成功返回字符ASCII码,失败返回EOF  
*/
行读写
c
// 读取一行  
char *fgets(char *s, int size, FILE *stream);  
/*  
@描述:  
    从文件流读取一行  
@s:  
    存储字符串的空间  
@size:  
    最大读取字节数(包含结尾\0)  
@stream:  
    文件流指针  
@return:  
    成功返回s地址,失败返回NULL  
*/  

// 写入字符串  
int fputs(const char *s, FILE *stream);  
/*  
@描述:  
    写入字符串到文件流  
@s:  
    待写入字符串  
@stream:  
    文件流指针  
@return:  
    成功返回非负数,失败返回EOF  
*/

注意fputsputs区别:

  • fputs可指定输出流,无自动换行
  • puts固定输出到stdout,自动添加\n
直接读写
c
// 块读取  
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);  
/*  
@描述:  
    从文件流读取数据块  
@ptr:  
    存储数据的内存地址  
@size:  
    单个元素大小  
@nmemb:  
    元素个数  
@stream:  
    文件流指针  
@return:  
    成功返回实际读取的元素个数  
*/  

// 块写入  
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);  
/*  
@描述:  
    写入数据块到文件流  
@ptr:  
    待写入数据地址  
@size:  
    单个元素大小  
@nmemb:  
    元素个数  
@stream:  
    文件流指针  
@return:  
    成功返回实际写入的元素个数  
*/

缓冲区控制

c
// 强制同步缓冲区  
int fflush(FILE *stream);  
/*  
@描述:  
    强制同步缓冲区数据到硬件  
@stream:  
    文件流指针(NULL表示刷新所有流)  
@return:  
    成功返回0,失败返回EOF  
*/  

// 设置缓冲区策略  
int setvbuf(FILE *stream, char *buf, int mode, size_t size);  
/*  
@描述:  
    设置缓冲区类型和大小  
@stream:  
    文件流指针  
@buf:  
    用户提供的缓冲区(需长期有效)  
@mode:  
    _IONBF(无缓冲)  
    _IOLBF(行缓冲)  
    _IOFBF(全缓冲)  
@size:  
    缓冲区大小  
@return:  
    成功返回0  
*/

文件定位

c
// 设置光标位置  
int fseek(FILE *stream, long offset, int whence);  
/*  
@描述:  
    移动文件流光标  
@stream:  
    文件流指针  
@offset:  
    偏移量(正数向后,负数向前)  
@whence:  
    SEEK_SET(文件开头)  
    SEEK_CUR(当前位置)  
    SEEK_END(文件末尾)  
@return:  
    成功返回0,失败返回-1  
*/  

// 获取光标位置  
long ftell(FILE *stream);  
/*  
@描述:  
    获取光标到文件头的字节数  
@stream:  
    文件流指针  
@return:  
    成功返回字节数,失败返回-1  
*/  

// 重置光标到文件头  
void rewind(FILE *stream);  
/*  
@描述:  
    重置光标到文件开头  
@stream:  
    文件流指针  
*/

错误处理

c
// 清除错误标志  
void clearerr(FILE *stream);  

// 检测文件结束  
int feof(FILE *stream);  
/*  
@return:  
    文件结束返回非0,否则返回0  
*/  

// 检测文件错误  
int ferror(FILE *stream);  
/*  
@return:  
    出错返回非0,否则返回0  
*/

格式化I/O

格式化输入
c
// 从文件流格式化输入  
int fscanf(FILE *stream, const char *format, ...);  

// 从字符串格式化输入  
int sscanf(const char *str, const char *format, ...);
格式化输出
c
// 输出到文件流  
int fprintf(FILE *stream, const char *format, ...);  

// 输出到字符串  
int sprintf(char *str, const char *format, ...);

格式化字符串规则

  1. 普通字符:必须精确匹配输入
  2. 格式化字符%d, %s, %c, %f...
  3. 转义字符\n, \t, \x89...

C++文件操作

cpp
#include <fstream>  

// 文件写入  
ofstream;  
// 文件读取  
ifstream;  
// 文件读写  
fstream;  

// 打开文件  
void open(const char *filename, ios::openmode mode);

打开模式

  • ios::in:读模式
  • ios::out:写模式
  • ios::ate:初始位置在文件尾
  • ios::app:追加模式
  • ios::trunc:存在则截断
  • ios::binary:二进制模式

作业

  1. 封装标准IO操作为C++类
  2. 完成目录拷贝作业

知识如风,常伴吾身