五、文件顺序读写(从头依次读写)
1. 读写函数总表
| 函数 | 作用 | 适用范围 |
|---|---|---|
| fgetc | 读取单个字符 | 所有输入流(文件 /stdin) |
| fputc | 写入单个字符 | 所有输出流(文件 /stdout) |
| fgets | 读取一行字符串 | 所有输入流 |
| fputs | 写入一行字符串 | 所有输出流 |
| fscanf | 格式化读取 | 所有输入流 |
| fprintf | 格式化写入 | 所有输出流 |
| fread | 二进制批量读 | 仅文件输入流 |
| fwrite | 二进制批量写 | 仅文件输出流 |
fgetc 详细用法
1. 功能
从已打开的文件流中读取1 个字符,读取完成后,文件内部的位置指针会自动向后移动 1 字节。
2. 函数原型
int fgetc(FILE *stream);
- 参数
stream:已经打开的文件指针(即fopen返回的FILE*)。 - 返回值:
- 成功:返回读取到的字符的 ASCII 码值(
int类型) - 读到文件末尾 / 读取失败:返回
EOF(标准宏,值通常为-1)
- 成功:返回读取到的字符的 ASCII 码值(
为什么返回
int而不是char? 若char是无符号类型,EOF(-1)无法用char正确表示;用int可以兼容所有字符 + 错误 / 末尾标记。
3. 典型用法:遍历读取整个文件
int ch; // 必须用int接收,不能用char
while ((ch = fgetc(pf)) != EOF)
{
printf("%c", ch); // 打印读到的字符
}
fputc 详细用法
1. 功能
将 1 个字符写入到已打开的文件流中,写入完成后,文件内部位置指针自动向后移动 1 字节。
2. 函数原型
int fputc(int character, FILE *stream);
- 参数 1
character:要写入的字符(传char类型会自动提升为int) - 参数 2
stream:目标文件指针。 - 返回值:
- 成功:返回写入的字符本身
- 失败:返回
EOF
3. 典型用法:逐个写入字符
// 文件必须以写模式打开,如 "w" / "a"
fputc('a', pf); // 写入字符 'a'
fputc('\n', pf); // 写入换行符
四、示例
示例 1:用 fgetc 读取文件并打印
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
FILE* pf = fopen("C:/Users/Edbsee/Desktop/test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch;
while ((ch = fgetc(pf)) != EOF)
{
printf("%c", ch);
}
fclose(pf);
pf = NULL;
return 0;
}
示例 2:用 fputc 写入文件
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
// w模式:文件不存在则创建,存在则清空原有内容
FILE* pf = fopen("C:/Users/Edbsee/Desktop/test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char str[] = "hello world";
for (int i = 0; str[i] != '\0'; i++)
{
fputc(str[i], pf);
}
fclose(pf);
pf = NULL;
printf("写入完成\n");
return 0;
}
fgets 详细用法
1. 功能
从指定文件流中读取一行字符,存入字符数组,遇到换行符 \n 或读满最大字符数 - 1 时停止,并自动在字符串末尾追加结束符 \0。
注意:读取到的换行符
\n会被一并存入字符串中,不会被丢弃。
2. 函数原型
char *fgets(char *str, int num, FILE *stream);
- 参数:
str:目标字符数组的首地址,用于存放读取到的字符串num:最多读取的字符总数(包含末尾自动添加的\0,因此实际最多读取num-1个有效字符)stream:已打开的文件指针
- 返回值:
- 读取成功:返回字符数组
str的首地址 - 读到文件末尾 / 读取失败:返回
NULL
- 读取成功:返回字符数组
3. 典型用法:逐行读取整个文件
char buf[1024]; // 存放一行内容的缓冲区
while (fgets(buf, sizeof(buf), pf) != NULL)
{
printf("%s", buf); // 直接打印,因为buf里自带换行符
}
fputs 详细用法
1. 功能
将一个字符串写入指定文件流,只写入字符串内容(到 \0 为止,\0 本身不写入),不会自动添加换行符。
2. 函数原型
int fputs(const char *str, FILE *stream);
- 参数:
str:要写入的字符串首地址stream:目标文件指针
- 返回值:
- 写入成功:返回非负整数
- 写入失败:返回
EOF
3. 典型用法:写入一行内容
fputs("hello world\n", pf); // 要换行必须手动加 \n
fputs("第二行内容\n", pf);
四、示例
示例 1:用 fgets 逐行读取文件
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
FILE* pf = fopen("C:/Users/Edbsee/Desktop/test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char buf[1024]; // 一行最多读1023个字符 + 1个\0
while (fgets(buf, sizeof(buf), pf) != NULL)
{
printf("%s", buf);
}
fclose(pf);
pf = NULL;
return 0;
}
示例 2:用 fputs 写入多行到文件
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
FILE* pf = fopen("C:/Users/Edbsee/Desktop/test.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputs("第一行:C语言文件操作\n", pf);
fputs("第二行:fputs函数演示\n", pf);
fputs("第三行:手动加换行符\n", pf);
fclose(pf);
pf = NULL;
printf("写入完成\n");
return 0;
}
fprintf 详细用法
1. 功能
按照指定的格式字符串,将数据格式化后写入目标文件流。用法和 printf 完全一致,仅多了第一个文件指针参数。 fprintf(stdout, ...) 等价于 printf(...),可直接输出到屏幕。
2. 函数原型
int fprintf(FILE *stream, const char *format, ...);
- 参数:
stream:已打开的目标文件指针format:格式控制字符串,和printf的格式符完全通用(%d%s%f%c等)...:可变参数列表,对应格式符的待写入数据
- 返回值:
- 成功:返回实际写入的字符总数
- 失败:返回负值
3. 典型用法
// 写入字符串、整数、浮点数
fprintf(pf, "姓名:%s 年龄:%d 成绩:%.2f\n", "张三", 20, 95.5);
fscanf 详细用法
1. 功能
从文件流中按照指定格式读取数据,并存入对应的变量地址中。用法和 scanf 完全一致,仅多了第一个文件指针参数。 fscanf(stdin, ...) 等价于 scanf(...),可从键盘读取输入。
2. 函数原型
int fscanf(FILE *stream, const char *format, ...);
- 参数:
stream:已打开的源文件指针format:格式控制字符串,和scanf格式符通用...:可变参数列表,对应格式符的变量地址(必须传地址)
- 返回值:
- 成功:返回成功匹配并赋值的参数个数
- 读到文件末尾 / 读取失败:返回
EOF
3. 典型用法
char name[20];
int age;
float score;
// 按格式读取,变量必须传地址
fscanf(pf, "姓名:%s 年龄:%d 成绩:%f", name, &age, &score);
四、示例
示例 1:用 fprintf 写入结构化数据
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
FILE* pf = fopen("C:/Users/Edbsee/Desktop/student.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
// 写入3条学生信息,每条占一行
fprintf(pf, "%s %d %.1f\n", "张三", 20, 95.5);
fprintf(pf, "%s %d %.1f\n", "李四", 19, 88.0);
fprintf(pf, "%s %d %.1f\n", "王五", 21, 92.5);
fclose(pf);
pf = NULL;
printf("写入完成\n");
return 0;
}
示例 2:用 fscanf 读取结构化数据
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
FILE* pf = fopen("C:/Users/Edbsee/Desktop/student.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
char name[20];
int age;
float score;
// 循环读取,直到文件末尾
while (fscanf(pf, "%s %d %f", name, &age, &score) != EOF)
{
printf("姓名:%s,年龄:%d,成绩:%.1f\n", name, age, score);
}
fclose(pf);
pf = NULL;
return 0;
}
fwrite 详细用法
1. 功能
把内存中一块连续的二进制数据,按字节原样写入文件流,不做任何格式转换。参数是 void* 类型,支持任意数据类型的写入。
2. 函数原型
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
- 参数:
ptr:待写入数据的内存起始地址(数组、结构体变量地址等)size:单个数据块的字节大小count:要写入的数据块总个数stream:目标文件指针
- 返回值:实际成功写入的完整数据块个数(不是字节数)。正常情况下等于
count;若返回值小于count,说明写入出错或磁盘空间不足。
3. 典型用法
int arr[] = {1, 2, 3, 4, 5};
// 写入5个int型数据,每个数据大小为 sizeof(int)
fwrite(arr, sizeof(int), 5, pf);
fread 详细用法
1. 功能
从文件中读取连续的字节数据,原样存入内存缓冲区,不做格式解析。
2. 函数原型
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
- 参数:
ptr:存放读取数据的内存缓冲区起始地址size:单个数据块的字节大小count:要读取的数据块总个数stream:源文件指针
- 返回值:实际成功读取的完整数据块个数。
- 正常读取:等于
count - 读到文件末尾 / 读取出错:返回小于
count的数值 - 剩余字节不足 1 个数据块时,返回已读取的完整块数
- 正常读取:等于
3. 典型用法
int arr[5];
// 读取5个int大小的数据,存入arr数组
fread(arr, sizeof(int), 5, pf);
四、示例:结构体批量读写
这是 fread/fwrite 最常用的场景,直接批量读写结构体数据。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
// 定义学生结构体
typedef struct Stu
{
char name[20];
int age;
float score;
} Stu;
int main()
{
// ========== 1. fwrite 写入二进制文件 ==========
Stu arr[] = {
{"张三", 20, 95.5f},
{"李四", 19, 88.0f}
};
FILE* pf_w = fopen("student.dat", "wb"); // 二进制写模式 wb
if (pf_w == NULL)
{
perror("fopen write");
return 1;
}
size_t ret_w = fwrite(arr, sizeof(Stu), 2, pf_w);
printf("成功写入 %zu 个结构体\n", ret_w);
fclose(pf_w);
pf_w = NULL;
// ========== 2. fread 读取二进制文件 ==========
Stu read_arr[2];
FILE* pf_r = fopen("student.dat", "rb"); // 二进制读模式 rb
if (pf_r == NULL)
{
perror("fopen read");
return 1;
}
size_t ret_r = fread(read_arr, sizeof(Stu), 2, pf_r);
printf("成功读取 %zu 个结构体\n\n", ret_r);
// 打印读取结果
for (size_t i = 0; i < ret_r; i++)
{
printf("姓名:%s,年龄:%d,成绩:%.1f\n",
read_arr[i].name, read_arr[i].age, read_arr[i].score);
}
fclose(pf_r);
pf_r = NULL;
return 0;
}
2. 三组格式化函数对比
scanf / printf:针对标准输入输出的格式化的输入输出函数
fscanf / fprintf:针对所有输入输出流的格式化的输入输出函数
sscanf / sprintf:从一个字符串中提取格式化的数据,把格式化的数据转换成字符串
sprintf 详细用法
1. 功能
按照指定格式,将多个数据拼接成一个完整的字符串,存入目标字符数组,自动在末尾追加结束符 \0。 常用于数字转字符串、拼接多段文本、构造格式化字符串。
2. 函数原型
int sprintf(char *str, const char *format, ...);
- 参数:
str:目标字符数组的首地址,用来存放生成的字符串format:格式控制字符串,和printf规则完全一致...:可变参数,对应格式符的待写入数据
- 返回值:
- 成功:返回实际写入的字符个数(不包含末尾的
\0) - 失败:返回负值
- 成功:返回实际写入的字符个数(不包含末尾的
3. 典型用法
char buf[100];
// 拼接字符串、整数、浮点数
sprintf(buf, "姓名:%s 年龄:%d 成绩:%.1f", "张三", 20, 95.5);
三、sscanf 详细用法
1. 功能
从一个已有的字符串中,按照指定格式提取数据,存入对应的变量地址。 常用于解析结构化字符串、从一行文本中拆分出多个数据。
2. 函数原型
int sscanf(const char *str, const char *format, ...);
- 参数:
str:源字符串的首地址,即待解析的字符串format:格式控制字符串,和scanf规则完全一致...:可变参数,对应格式符的变量地址(必须传地址)
- 返回值:
- 成功:返回成功匹配并赋值的参数个数
- 解析失败 / 字符串读完:返回
EOF
3. 典型用法
char str[] = "张三 20 95.5";
char name[20];
int age;
float score;
// 从字符串中提取3个数据
sscanf(str, "%s %d %f", name, &age, &score);
四、示例
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
// ========== sprintf 演示 ==========
char buf[100];
int len = sprintf(buf, "学号:%d 姓名:%s 总分:%d\n", 1001, "李四", 580);
printf("生成的字符串:%s", buf);
printf("字符串长度:%d\n\n", len);
// ========== sscanf 演示 ==========
char data[] = "1002 王五 590";
int id;
char name[20];
int total;
int cnt = sscanf(data, "%d %s %d", &id, name, &total);
printf("成功解析 %d 个数据\n", cnt);
printf("学号:%d,姓名:%s,总分:%d\n", id, name, total);
return 0;
}
&spm=1001.2101.3001.5002&articleId=163395512&d=1&t=3&u=fa735b4bbd934e1ea0a493aac9662a37)
2万+

被折叠的 条评论
为什么被折叠?



