IO(Input & Output)操作,即输入 & 输出操作,是程序与系统、用户交互的重要渠道。程序可以从命令行、本地文件、网络、数据库以及其他途径获取输入,并向这些地方输出内容,这些操作合称 IO 操作。C 的IO操作部分定义于 stdio.h 头文件。
C 程序会将一切设备都视为文件,对设备的处理方式和一般文件无异。 C 使用文件指针来访问文件。
关于IO操作函数的详细解释见 stdio.h 。
命令行IO
在程序运行时,会自动打开以下三个文件以供基本的命令行输入输出。
| 名称 | 文件指针 | 设备 |
|---|---|---|
| 标准输入 | stdin | 键盘 |
| 标准输出 | stdout | 屏幕或命令行窗口 |
| 标准错误 | stderr | 屏幕或命令行窗口 |
这些文件输入、输出的背后,有一片临时存放数据的区域,称为缓冲区。从 stdin 输入的数据会先存入缓冲区,供程序读取;向 stdout 发送的输出会先送入缓冲区,达到某一条件时再传递数据给 stdout ; stderr 则不存在缓冲区,向其发送到数据会直接送入 stderr。
printf
printf 函数是最基本的输出函数,用于将内容输出到 stdout,然后在命令行窗口上呈现。
printf 定义如下:
1 | int printf(const char* format, ...); |
printf 函数返回输出的总字符数。
格式化字符串
printf 的输出即格式化输出,格式化字符串中的格式化占位符会被替换为对应格式的表达式值。这些占位符都以半角百分号 % 开头,每种占位符对应不同的数据类型。
1 | printf("This %s is %d years old.\n","dog",4); |
scanf
scanf 用于读取输入。在调用 scanf 函数时,程序会阻塞,直到可以从缓冲区读取数据。
scanf 定义如下:
1 | int scanf(const char* format, ...); |
gets & puts
gets 、 puts 用于读取、输出字符串,定义如下:
1 | char* gets(char* str); |
gets 相当于 scanf("%s",str),若读取成功则返回 str,读取失败则返回 NULL 。
puts 相当于 printf("%s\n",str),若输出成功则返回非负值,输出失败则返回 EOF 。
getchar & putchar
getchar 、 putchar 用于读取、输出单个字符,定义如下:
1 | int getchar(void); |
getchar 相当于 scanf("%c",c),若读取成功则返回字符对应的 ASCII 编码,读取失败则返回 EOF 。
putchar 相当于 printf("%c",c),若输出成功则返回字符对应的 ASCII 编码,输出失败则返回 EOF 。
文件IO
C 除了对 stdin 这种虚拟文件的读写,可也以读写真正的文件。使用 fopen 函数可以打开文件并创建文件指针(亦称文件流),然后即可对文件指针进行读写操作。
1 | FILE* fopen(const char* filename, const char* mode); |
mode 为文件的读写模式,有如下几种:
| 模式 | 描述 |
|---|---|
| r | 以只读模式打开文件,文件不存在则返回 NULL |
| w | 创建一个用于写入的空文件,如果文件已经存在会删除已有的文件再创建新文件 |
| a | 以追加模式打开文件,将写入的内容追加到原文件末尾,文件不存在则创建空文件 |
| r+ | 以读写模式打开文件,可以读取也可以写入,文件不存在则返回 NULL |
| w+ | 创建一个用于读写的空文件,如果文件已经存在会删除已有的文件再创建新文件 |
| a+ | 以追加与读取模式打开文件,文件不存在则创建空文件 |
mode可以附加参数b和t,例如wb+ rt ab。b表示以二进制模式读写,t表示以文本模式读写。
若读取打开成功则返回文件指针 FILE* ,失败则返回 NULL 并将错误储存在全局变量 errno 中(需 errno.h 头文件)并使用 strerror 函数查看错误信息。
1 |
|
在文件使用完毕后,使用 fclose 关闭文件,保存修改,释放资源。
在对文件进行读写操作时,确保和打开文件的模式匹配。
在打开文件时,文件会载入文件缓冲区,读写都在这个缓冲区中进行。但是与
stdin的缓冲区不同,读取文件缓冲区时不会移除已读取的数据,而是移动缓冲区中的数据游标到下一块数据的位置。通过fseek函数可以移动游标的位置。
在读取文件时,以
EOF结束文件数据。当读取到EOF时表示文件已经读取完毕。
fprintf
printf 的文件输出版本,定义如下:
1 | int fprintf(FILE* stream, const char* format, ...); |
除了是向文件输出内容,其余部分和 printf 完全一致。
fscanf
scanf 的文件输入版本,定义如下:
1 | int fscanf(FILE* stream, const char* format, ...); |
除了是从文件读取内容,其余部分和 scanf 完全一致。
fgets & fputs
分别为 gets 、 puts 的文件读写版本,定义如下:
1 | char* fgets(char* str, int n, FILE* stream);//n为要读取的字符数(包括字符串结束符的位置,实际读取的字符数为n-1) |
fgetc & fputc
分别为 getchar 、 putchar 的文件读写版本,定义如下:
1 | int fgetc(FILE* stream); |
fgetc如果读取到了缓冲区的结束符EOF则会返回EOF。
stdin和stdout作为虚拟文件,也可以使用这些函数进行读写。
写在最后
IO操作是程序最基本的一环之一,因为涉及程序外部的内容,在进行IO操作时一定要做好异常处理。