C语言 标准I/O函数全面指南
C标准I/O函数全面指南
本指南详细介绍了C语言中用于文件操作的标准输入/输出函数,包括单字符I/O、字符串I/O、格式化I/O、块I/O以及文件光标操作。每个部分包含函数定义、使用说明和实用示例,适合学习、复习以及博客发布。内容采用清晰的Markdown格式,代码规范,包含详细注释和最佳实践(如错误处理),以提升可读性和实用性。
1. 单字符读写:fputc
和 fgetc
函数定义
-
fgetc
#include <stdio.h> int fgetc(FILE *stream);
- 功能:从指定文件中读取一个字符,并以无符号整数形式返回。
- 参数:
stream
- 文件指针。 - 返回值:
- 成功:返回读取的字符(无符号整数形式)。
- 失败:返回
EOF
并设置错误码。
-
fputc
#include <stdio.h> int fputc(int c, FILE *stream);
- 功能:将指定字符
c
写入到文件指针stream
指向的文件中。 - 参数:
c
:要写入的字符(以无符号整数形式传递)。stream
:文件指针。
- 返回值:
- 成功:返回写入的字符(无符号整数形式)。
- 失败:返回
EOF
并设置错误码。
- 功能:将指定字符
示例代码
以下示例展示如何使用fputc
写入字符到文件,并用fgetc
读取文件内容。
#include <stdio.h>int main() {// 定义文件指针FILE *fp = NULL;// 以只写模式打开文件if ((fp = fopen("file.txt", "w")) == NULL) {perror("fopen error");return -1;}// 写入字符串 "Hello",每次写入一个字符fputc('H', fp);fputc('e', fp);fputc('l', fp);fputc('l', fp);fputc('o', fp);fclose(fp); // 关闭文件// 以只读模式重新打开文件if ((fp = fopen("file.txt", "r")) == NULL) {perror("fopen error");return -1;}// 逐字符读取并打印char ch;while ((ch = fgetc(fp)) != EOF) {printf("%c ", ch);}fclose(fp); // 关闭文件return 0;
}
说明
- 写入:
fputc
每次写入一个字符,文件光标自动向后移动。 - 读取:
fgetc
每次读取一个字符,遇到文件末尾返回EOF
。 - 注意:写入后光标位于文件末尾,直接读取会失败,因此需重新打开文件或使用
rewind
重置光标。
2. 字符串读写:fgets
和 fputs
函数定义
-
fputs
#include <stdio.h> int fputs(const char *s, FILE *stream);
- 功能:将字符串
s
写入到文件指针stream
指向的文件中(不包含字符串结束符\0
)。 - 参数:
s
:要写入的字符串。stream
:文件指针。
- 返回值:
- 成功:返回写入的字符数(非负数)。
- 失败:返回
EOF
。
- 功能:将字符串
-
fgets
#include <stdio.h> char *fgets(char *s, int size, FILE *stream);
- 功能:从文件指针
stream
指向的文件中读取最多size-1
个字符到数组s
,遇到换行符或文件末尾停止,并在末尾自动添加\0
。 - 参数:
s
:存储读取数据的字符数组。size
:最多读取的字符数(包含末尾\0
)。stream
:文件指针。
- 返回值:
- 成功:返回
s
(字符数组起始地址)。 - 失败或文件末尾:返回
NULL
。
- 成功:返回
- 功能:从文件指针
示例代码
以下示例展示如何从终端输入字符串并写入文件,再从文件中读取并显示。
#include <stdio.h>
#include <string.h>int main() {// 定义文件指针FILE *fp = NULL;// 以只写模式打开文件if ((fp = fopen("file.txt", "w")) == NULL) {perror("fopen error");return -1;}// 从终端输入字符串并写入文件char wbuf[128];while (1) {printf("请输入字符串(输入quit退出):");fgets(wbuf, sizeof(wbuf), stdin); // 从标准输入读取wbuf[strcspn(wbuf, "\n")] = '\0'; // 移除换行符if (strcmp(wbuf, "quit") == 0) {break;}fputs(wbuf, fp); // 写入字符串fputc('\n', fp); // 添加换行符}fclose(fp);// 以只读模式打开文件if ((fp = fopen("file.txt", "r")) == NULL) {perror("fopen error");return -1;}// 逐行读取并打印char rbuf[128];while (fgets(rbuf, sizeof(rbuf), fp) != NULL) {printf("读取到:%s", rbuf);}fclose(fp);return 0;
}
说明
- 写入:
fputs
写入字符串,不包括\0
,需手动添加换行符以分隔行。 - 读取:
fgets
读取一行(包含换行符),自动添加\0
,适合逐行处理文本文件。 - 注意:
fgets
会保留输入的换行符,需用strcspn
或类似方法移除。
3. 格式化读写:fprintf
和 fscanf
函数定义
-
fprintf
#include <stdio.h> int fprintf(FILE *stream, const char *format, ...);
- 功能:按指定格式将数据写入文件。
- 参数:
stream
:文件指针(可为stdout
或stderr
)。format
:格式化字符串,包含格式控制符(如%d
、%s
、%f
、%lf
)。...
:可变参数,数量由格式控制符决定。
- 返回值:
- 成功:返回写入的字符数。
- 失败:返回负数。
-
fscanf
#include <stdio.h> int fscanf(FILE *stream, const char *format, ...);
- 功能:按指定格式从文件中读取数据到变量中。
- 参数:
stream
:文件指针(可为stdin
)。format
:格式化字符串,包含格式控制符。...
:变量地址列表,数量由格式控制符决定。
- 返回值:
- 成功:返回成功读取的项数。
- 失败或文件末尾:返回
EOF
并设置错误码。
示例代码
以下示例展示格式化读写到标准输出/输入和外部文件。
#include <stdio.h>int main() {// 向标准输出写入格式化数据fprintf(stdout, "整数: %d, 小数: %.2f, 字符串: %s\n", 520, 3.14, "I Love C");// 从标准输入读取整数int num;printf("请输入一个整数:");if (fscanf(stdin, "%d", &num) == 1) {printf("读取到:%d\n", num);} else {printf("读取失败\n");}// 写入格式化数据到文件FILE *fp = NULL;if ((fp = fopen("usr.txt", "w")) == NULL) {perror("fopen error");return -1;}fprintf(fp, "%s %d", "admin", 123456); // 写入用户名和密码fclose(fp);// 从文件中读取格式化数据if ((fp = fopen("usr.txt", "r")) == NULL) {perror("fopen error");return -1;}char usrName[20];int pwd;if (fscanf(fp, "%s %d", usrName, &pwd) == 2) {printf("用户名: %s, 密码: %d\n", usrName, pwd);} else {printf("读取失败\n");}fclose(fp);return 0;
}
说明
- 格式化:
fprintf
和fscanf
支持多种数据类型(如整数、浮点数、字符串),灵活性高。 - 标准I/O:使用
stdout
或stdin
可直接操作终端输入输出。 - 注意:
fscanf
读取时需确保变量地址正确,格式匹配,否则可能导致错误。
4. 格式串转字符串:sprintf
和 snprintf
函数定义
-
sprintf
#include <stdio.h> int sprintf(char *str, const char *format, ...);
- 功能:将格式化数据转换为字符串,存储到字符数组
str
中。 - 参数:
str
:目标字符数组。format
:格式化字符串。...
:可变参数。
- 返回值:
- 成功:返回转换的字符数(不含
\0
)。 - 失败:返回
EOF
。
- 成功:返回转换的字符数(不含
- 功能:将格式化数据转换为字符串,存储到字符数组
-
snprintf
#include <stdio.h> int snprintf(char *str, size_t size, const char *format, ...);
- 功能:将格式化数据转换为字符串,最多存储
size-1
个字符到str
,并添加\0
。 - 参数:
str
:目标字符数组。size
:最大存储字符数(含\0
)。format
:格式化字符串。...
:可变参数。
- 返回值:
- 成功:返回应写入的字符数(不含
\0
)。 - 如果超出
size
:返回应写入的字符数(但只写入size-1
个字符)。 - 失败:返回
EOF
。
- 成功:返回应写入的字符数(不含
- 功能:将格式化数据转换为字符串,最多存储
示例代码
以下示例展示如何将多种数据类型组合成字符串。
#include <stdio.h>int main() {char buf[20];// 使用 sprintf(不安全,可能溢出)sprintf(buf, "%d %s %.1f", 1001, "zhangsan", 99.5);printf("sprintf结果: %s\n", buf);// 使用 snprintf(安全,限制长度)snprintf(buf, sizeof(buf), "%d %s %.1f", 1001, "zhangsan", 99.5);printf("snprintf结果: %s\n", buf);return 0;
}
说明
- 安全性:
sprintf
可能导致缓冲区溢出,推荐使用snprintf
以限制写入长度。 - 用途:常用于将多种数据类型组合成字符串,便于后续处理或输出。
- 注意:确保
buf
大小足够容纳格式化结果,snprintf
更适合现代编程。
5. 模块化读写:fread
和 fwrite
函数定义
-
fread
#include <stdio.h> size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
- 功能:从文件读取
nmemb
项数据,每项大小为size
字节,存储到ptr
指向的内存。 - 参数:
ptr
:存储数据的内存地址(支持任意类型)。size
:每项数据的大小(字节)。nmemb
:读取的项数。stream
:文件指针。
- 返回值:
- 成功:返回实际读取的项数。
- 失败或文件末尾:返回小于
nmemb
的值或0。
- 功能:从文件读取
-
fwrite
#include <stdio.h> size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
- 功能:将
ptr
指向的nmemb
项数据(每项size
字节)写入文件。 - 参数:
ptr
:要写入的数据地址。size
:每项数据的大小(字节)。nmemb
:写入的项数。stream
:文件指针。
- 返回值:
- 成功:返回实际写入的项数。
- 失败:返回小于
nmemb
的值或0。
- 功能:将
示例代码
字符串读写
#include <stdio.h>
#include <string.h>int main() {FILE *fp = NULL;// 以只写模式打开文件if ((fp = fopen("test.txt", "w")) == NULL) {perror("fopen error");return -1;}// 循环输入字符串并写入char wbuf[128];while (1) {printf("请输入字符串(输入quit退出):");fgets(wbuf, sizeof(wbuf), stdin);wbuf[strcspn(wbuf, "\n")] = '\0';if (strcmp(wbuf, "quit") == 0) {break;}fwrite(wbuf, strlen(wbuf), 1, fp); // 写入字符串fwrite("\n", 1, 1, fp); // 添加换行fflush(fp); // 刷新缓冲区}fclose(fp);// 以只读模式打开文件if ((fp = fopen("test.txt", "r")) == NULL) {perror("fopen error");return -1;}// 读取并输出char rbuf[10];size_t res;while ((res = fread(rbuf, 1, sizeof(rbuf) - 1, fp)) > 0) {rbuf[res] = '\0'; // 添加结束符fwrite(rbuf, 1, res, stdout); // 输出到终端}fclose(fp);return 0;
}
整数读写
#include <stdio.h>int main() {FILE *fp = NULL;// 以只写模式打开文件if ((fp = fopen("test.txt", "w")) == NULL) {perror("fopen error");return -1;}// 写入整数int num = 16;fwrite(&num, sizeof(int), 1, fp);fclose(fp);// 以只读模式打开文件if ((fp = fopen("test.txt", "r")) == NULL) {perror("fopen error");return -1;}// 读取整数int key;if (fread(&key, sizeof(int), 1, fp) == 1) {printf("读取到: %d\n", key);} else {printf("读取失败\n");}fclose(fp);return 0;
}
结构体读写
#include <stdio.h>
#include <string.h>typedef struct {char name[20];int age;double score;
} Stu;int main() {FILE *fp = NULL;// 以只写模式打开文件if ((fp = fopen("test.txt", "w")) == NULL) {perror("fopen error");return -1;}// 定义并写入学生数据Stu students[] = {{"张三", 18, 98.0},{"李四", 20, 88.0},{"王五", 16, 95.0}};fwrite(students, sizeof(Stu), 3, fp);fclose(fp);// 以只读模式打开文件if ((fp = fopen("test.txt", "r")) == NULL) {perror("fopen error");return -1;}// 读取并显示一个学生信息Stu temp;if (fread(&temp, sizeof(Stu), 1, fp) == 1) {printf("姓名: %s, 年龄: %d, 成绩: %.2f\n", temp.name, temp.age, temp.score);}fclose(fp);return 0;
}
说明
- 灵活性:
fread
和fwrite
支持任意数据类型(如字符串、整数、结构体),适合二进制文件操作。 - 注意:二进制读写需确保数据结构对齐一致,跨平台时需考虑字节序。
6. 文件光标操作:fseek
, ftell
, rewind
函数定义
-
fseek
#include <stdio.h> int fseek(FILE *stream, long offset, int whence);
- 功能:移动文件光标到指定位置。
- 参数:
stream
:文件指针。offset
:偏移量(正:向后,负:向前,0:不动)。whence
:起始位置(SEEK_SET
:文件开头,SEEK_CUR
:当前位置,SEEK_END
:文件末尾)。
- 返回值:
- 成功:返回0。
- 失败:返回-1并设置错误码。
-
ftell
#include <stdio.h> long ftell(FILE *stream);
- 功能:获取文件光标的当前偏移量(相对于文件开头)。
- 参数:
stream
- 文件指针。 - 返回值:
- 成功:返回当前偏移量(字节)。
- 失败:返回-1并设置错误码。
-
rewind
#include <stdio.h> void rewind(FILE *stream);
- 功能:将文件光标重置到文件开头(等效于
fseek(stream, 0, SEEK_SET)
)。 - 参数:
stream
- 文件指针。 - 返回值:无。
- 功能:将文件光标重置到文件开头(等效于
示例代码
以下示例展示如何操作文件光标并读取特定位置的数据。
#include <stdio.h>
#include <string.h>typedef struct {char name[20];int age;double score;
} Stu;int main() {FILE *fp = NULL;// 以读写模式打开文件if ((fp = fopen("test.txt", "w+")) == NULL) {perror("fopen error");return -1;}// 写入三个学生数据Stu students[] = {{"张三", 18, 98.0},{"李四", 20, 88.0},{"王五", 16, 95.0}};fwrite(students, sizeof(Stu), 3, fp);// 获取文件大小fseek(fp, 0, SEEK_END);printf("文件大小: %ld 字节\n", ftell(fp));// 移动光标到第二个学生fseek(fp, sizeof(Stu), SEEK_SET);// 读取并显示第二个学生信息Stu temp;if (fread(&temp, sizeof(Stu), 1, fp) == 1) {printf("姓名: %s, 年龄: %d, 成绩: %.2f\n", temp.name, temp.age, temp.score);}fclose(fp);return 0;
}
说明
- 光标操作:
fseek
灵活控制文件读取位置,ftell
可用于计算文件大小。 - 重置光标:
rewind
适合在同一文件流中从头重新读取。 - 注意:二进制文件操作时,偏移量需与数据结构大小对齐。
总结与注意事项
- 文件操作流程:始终检查
fopen
返回值,确保文件打开成功;操作完成后使用fclose
关闭文件。 - 错误处理:使用
perror
或检查返回值捕获错误,确保程序健壮性。 - 缓冲区管理:写入数据后可用
fflush
刷新缓冲区,确保数据及时写入。 - 安全性:优先使用
snprintf
而非sprintf
,避免缓冲区溢出。 - 跨平台注意:二进制文件读写需考虑字节序和结构体对齐问题。