一、文件的作用
文件的核心作用就是:把数据从易失的内存,存到持久的硬盘里,程序退出了数据也不会丢。
二、文件是什么?
在 C 语言里,我们说的文件主要分两大类:
2.1 程序文件
程序文件: 就是和 "程序本身" 相关的文件 ,比如你写的**.c源代码、编译生成的.obj目标文件、最终的.exe可执行文件** ,这些都是用来构成和运行程序的。
2.2 数据文件
数据文件: 就是程序运行时用来读写数据 的文件,内容不一定是代码,比如你存的用户信息、程序日志、配置文件,程序从里面读数据,也能把结果写到里面去。
2.3 文件名
文件名 其实是文件的唯一标识,用来定位和区分不同文件,完整的标识包含三部分:
- 文件路径 :文件在磁盘上的位置,比如
c:\code\ - 文件名主干 :文件的名字,比如
test - 文件后缀 :表示文件类型,比如
.txt
举个例子 :c:\code\test.txt
- 路径:
c:\code\ - 主干:
test - 后缀:
.txt
三、核心概念:文本文件 vs 二进制文件
这张图讲的是数据在外存(硬盘)上的两种存储方式:
| 存储方式 | 存储规则 | 示例(整数 10000) | 占用空间 |
|---|---|---|---|
| 文本文件(ASCII 形式) | 所有数据都按 ASCII 字符存储,数值会被拆成字符 | '1' '0' '0' '0' '0' |
5 字节 |
| 二进制文件 | 直接把内存中的二进制数据原封不动写入文件 | 00000000 00000000 00100111 00010000 |
4 字节(int 类型占 4 字节) |
💡 关键区别:
- 文本文件:人能直接看懂(比如用记事本打开),但会额外占用空间,读写时需要转换。
- 二进制文件:和内存中的数据结构完全一致,读写速度快,空间更省,但人无法直接看懂。
3.1 整数 10000 的两种存储
-
内存中的形式
10000作为int类型,在内存中是 4 字节的二进制:00000000 00000000 00100111 00010000(十进制转二进制结果)。 -
ASCII 形式(文本文件) 会把
10000拆成 5 个字符:'1' '0' '0' '0' '0',每个字符的 ASCII 码是:'1'→00110001(49)'0'→00110000(48)所以文件里会存这 5 个字节:00110001 00110000 00110000 00110000 00110000,共 5 字节。
-
二进制形式(二进制文件) 直接把内存中的 4 字节原封不动写入文件,文件里就是:
00000000 00000000 00100111 00010000,共 4 字节 。用 VS 的二进制编辑器打开,会看到十六进制:00 00 27 10(和二进制一一对应)。
3.2 演示代码解读
#include <stdio.h>
int main()
{
int a = 10000;
FILE* pf = fopen("test.txt", "wb"); // "wb" 表示:以二进制模式写文件
fwrite(&a, 4, 1, pf); // 从变量a的地址开始,写4个字节,写1次
fclose(pf);
pf = NULL;
return 0;
}
fopen的"wb"模式是关键:w表示写 ,b表示二进制 (binary),不加b就是文本模式。fwrite直接把a的内存数据原封不动写入文件,所以生成的是二进制文件。


文件中产生的是乱码 因为这是在文本文档中不是在二进制文件中


这时候文件中的内容就是二进制10000的二进制序列
3.3 VS 中查看二进制文件的方法
- 在 VS 的「解决方案资源管理器」中,右键
test.txt。 - 选择「打开方式」。
- 在弹出的窗口中,选择「二进制编辑器」。
- 打开后就能看到文件的十六进制内容:
00 00 27 10,和我们前面分析的一致。
四、文件的打开和关闭
思路:打开文件--->读写文件--->关闭文件
4.1 核心概念:流、标准流与文件指针
1. 流(Stream)
- 流是C 语言中对外部设备 (文件、键盘、屏幕等**)数据交互的抽象概念** ,可以理解为数据流动的通道。
- 所有输入输出操作 (如键盘输入、屏幕打印、文件读写),都是通过 "流" 来完成的。
- 流操作自带缓冲区 ,目的是减少直接读写硬盘的次数 ,提高效率。
2. 标准流(程序默认打开的 3 个流)
C 程序启动时,会自动打开 3 个流 ,无需手动 fopen:
| 流名 | 含义 | 用途 |
|---|---|---|
stdin |
标准输入流 | 从键盘读取数据,scanf 函数使用它 |
stdout |
标准输出流 | 向屏幕打印数据,printf 函数使用它 |
stderr |
标准错误流 | 向屏幕输出错误信息 |
- 这三个流的类型都是
FILE*(文件指针),和文件操作的指针是同一种类型。
3. 文件指针(FILE*)
- 每个被打开的文件 ,都会在内存中 创建一个 文件信息区 (
FILE结构体变量),存储文件名、状态、读写位置等信息。 FILE*就是指向这个结构体的指针 ,我们通过它来间接操作文件。- 不同编译器的
FILE结构体细节不同 (如 VS 的struct _iobuf),但用法一致,开发者无需关心内部实现。
4.2 文件的打开与关闭:fopen 和 fclose
1. fopen 函数(打开文件)
FILE *fopen(const char *filename, const char *mode);
- 参数 :
-
filename:要打开的文件名 (可以是相对路径或绝对路径)。 -
绝对路径
"盘符:/文件夹/文件名.后缀" "E:/project/data.txt"相对路径
同级:直接写文件名 子级:文件夹/文件名 上级:../文件名 -
mode:文件打开方式 (核心参数,决定读写权限和文件类型)。
-
- 返回值 :
- 成功:返回一个
FILE*类型的指针 ,指向该文件的信息区。 - 失败:返回 NULL,必须做判空处理,否则会引发程序崩溃。
- 成功:返回一个
cpp
#include<stdio.h>
int main()
{
FILE* pf= fopen("test.txt","r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
//关闭为文件
fclose(pf);
pf = NULL;
}

常用mode 对照表
| 模式 | 含义 | 文件不存在时 | 文件存在时 |
|---|---|---|---|
"r" |
只读(文本文件) | 报错 | 打开,只读 |
"w" |
只写(文本文件) | 创建新文件 | 清空原有内容 ,只写 |
"a" |
追加(文本文件) | 创建新文件 | 在文件末尾追加数据 |
"rb" |
只读(二进制文件) | 报错 | 打开,只读 |
"wb" |
只写(二进制文件) | 创建新文件 | 清空原有内容,只写 |
"ab" |
追加(二进制文件) | 创建新文件 | 在文件末尾追加数据 |
"r+" |
读写(文本文件) | 报错 | 打开,可读写 |
"w+" |
读写(文本文件) | 创建新文件 | 清空原有内容,可读写 |
"a+" |
读写(文本文件) | 创建新文件 | 末尾追加 + 读 |
2. fclose 函数(关闭文件)
int fclose(FILE *stream);
- 功能 :关闭文件 ,刷新缓冲区 ,释放文件信息区的资源。
- 返回值 :成功返回
0,失败返回EOF。 - 注意:文件使用完必须关闭 ,否则会导致数据未写入 、资源泄漏 。关闭后建议将指针置为
NULL,避免野指针。
4.3 完整示例代码(打开 + 关闭)
#include <stdio.h>
int main()
{
// 1. 打开文件,只读模式
FILE* fp = fopen("test.txt", "r");
if (fp == NULL) // 必须判空!
{
perror("fopen"); // 打印错误信息
return 1;
}
printf("文件打开成功,可以进行读写操作\n");
// 2. 关闭文件
fclose(fp);
fp = NULL; // 置空,避免野指针
return 0;
}
4.4 避坑指南与关键细节
- 必须判空 :
fopen失败会返回NULL,如果直接使用空指针操作文件,会导致程序崩溃。 - 关闭文件:不关闭文件会导致缓冲区数据未写入硬盘,文件内容丢失;同时占用系统资源。
- 文本 vs 二进制模式 :
- 文本模式下,Windows 系统会自动将
\n转换为\r\n写入文件,读取时再转换回来。 - 二进制模式下,数据原封不动读写,不会做任何转换,适合图片、视频等非文本数据。
- 文本模式下,Windows 系统会自动将
- 路径问题 :Windows 下路径分隔符是
\,但 C 语言中\是转义字符,所以路径要写成D:\\test.txt或D:/test.txt。 "w"模式会清空文件 :使用"w"或"wb"打开已存在的文件时,文件内容会被直接清空,操作前一定要确认。
五、文件顺序读写
5.1 函数总览
| 函数名 | 功能 | 适用范围 |
|---|---|---|
fgetc |
从输入流读取单个字符 | 所有输入流(文件、stdin) |
fputc |
向输出流写入单个字符 | 所有输出流(文件、stdout) |
fgets |
从输入流读取字符串 | 所有输入流 |
fputs |
向输出流写入字符串 | 所有输出流 |
fscanf |
从输入流读取格式化数据 | 所有输入流 |
fprintf |
向输出流写入格式化数据 | 所有输出流 |
fread |
读取一块二进制数据 | 仅文件输入流 |
fwrite |
写入一块二进制数据 | 仅文件输出流 |
5.2 字符读写函数
1. fputc 写入单个字符
- 原型:
int fputc(int character, FILE *stream); - 参数:
character:待写入字符stream:文件指针 / 输出流(stdout--屏幕)
- 返回值:成功返回写入的字符(int 型) ;失败返回**
EOF(-1)**
示例 1:写入单个字符
#include <stdio.h>
int main()
{
FILE* fp = fopen("test.txt", "w"); // w模式:清空原有内容,新建文件写入
if(fp == NULL)
{
perror("fopen");
return 1;
}
fputc('a', fp);
fputc('b', fp);
fputc('c', fp);
fclose(fp); // 关闭文件
fp = NULL; // 置空避免野指针
return 0;
}

示例 2:循环写入 a-z 所有字符
#include <stdio.h>
int main()
{
FILE* fp = fopen("test.txt", "w");
if(fp == NULL)
{
perror("fopen");
return 1;
}
int ch = 0;
for(ch = 'a'; ch <= 'z'; ch++)
{
fputc(ch, fp);
}
fclose(fp);
fp = NULL;
return 0;
}

2. fgetc 读取单个字符
- 原型:int fgetc(FILE *stream)
; - 参数:
stream:文件指针 / 输入流(stdin--键盘) - 返回值:成功返回读取的字符(int 型) ;读到末尾 / 出错返回**
EOF(-1)**
示例:读取文件前 10 个字符并打印
#include <stdio.h>
int main()
{
FILE* fp = fopen("test.txt", "r"); // r模式:只读
if(fp == NULL)
{
perror("fopen");
return 1;
}
int i = 0;
for(i = 0; i < 10; i++)
{
int c = fgetc(fp);
fputc(c, stdout); // stdout:标准输出(控制台)
}
fclose(fp);
fp = NULL;
return 0;
}
cpp
//读取文件中数据 打印文件中给所有数据
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.tst", "r");//读文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = 0;
while ((ch = fgetc(pf)) != EOF)
{
printf("%c",ch);
}
fclose(pf);//关闭文件
pf = NULL;
return 0;
}

3. feof & ferror 状态检测
feof
- 原型:
int feof(FILE *stream);//用于检测stream指针指向的流是否遇到文件末尾 - 参数:
stream:文件指针 - 返回值:到文件末尾返回非 0;未到末尾返回 0
ferror
- 原型:
int ferror(FILE *stream);//用于检测stream指针指向的流是否发生读写错误 - 参数:
stream:文件指针 - 返回值:读写出错返回非 0;无错误返回 0
示例 1:feof 判断文件末尾
#include <stdio.h>
int main()
{
FILE* fp = fopen("test.txt", "r");
if(fp == NULL)
{
perror("fopen");
return 1;
}
int c = 0;
while((c = fgetc(fp)) != EOF) // 循环读取,直到末尾
{
fputc(c, stdout);
}
if(feof(fp))
printf("\n读到文件末尾\n");
else if(ferror(fp))
printf("\n读取出错\n");
fclose(fp);
fp = NULL;
return 0;
}
示例 2:ferror 判断读写错误
#include <stdio.h>
int main()
{
FILE* fp = fopen("test.txt", "w"); // 只写模式,不能读,会触发错误
if(fp == NULL)
{
perror("fopen");
return 1;
}
int c = fgetc(fp); // 尝试读取,触发错误
if(c == EOF)
{
if(ferror(fp))
printf("读取出错\n");
}
fclose(fp);
fp = NULL;
return 0;
}
5.3 字符串读写函数
1. fputs 写入字符串
- 原型:int fputs(const char str, FILE stream);
//将str指向的字符串写入到参数stream指定的流中(不包含结尾的\0),使用于文件流或者标准输出(stdout)** - 参数:
str:待写入字符串stream:文件指针 / 输出流
- 返回值:成功返回非负数 ;失败返回**
EOF(-1)**
示例:写入字符串 (要想写入两行我们要自行换行)
cpp
//fputs输入字符串到文件中
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.tst", "w");//写文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputs("hello", pf);
fputs("world", pf);
fclose(pf);//关闭文件
pf = NULL;
return 0;
}

2. fgets 读取字符串
- 原型:**char *fgets(char str, int num, FILE stream)
;//将stream中读指定字符串并放到str指向的空间中 - 参数:
str:存储读取内容的字符数组num:最大读取字符数(包含结尾的\0 ,实际最多放num-1个字符)stream:文件指针 / 输入流
- 返回值:成功返回str 地址 ;末尾 / 出错返回**
NULL**
示例:读取文件两行内容
#include <stdio.h>
int main()
{
FILE* fp = fopen("test.txt", "r");
if(fp == NULL)
{
perror("fopen");
return 1;
}
char arr1[10] = {0};
char arr2[10] = {0};
fgets(arr1, sizeof(arr1), fp); // 读取第一行
fgets(arr2, sizeof(arr2), fp); // 读取第二行
printf("%s", arr1);
printf("%s", arr2);
fclose(fp);
fp = NULL;
return 0;
}
或者运用循环
cpp
//用fgets读取文件
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.tst", "r");//写文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
char arr[20] = "-----------";
/*fgets(arr, 5, pf);*///abcd\0
//如果有多行数据 运用循环
while ((fgets(arr, 20, pf)) != NULL)
{
printf("%s ", arr);
}
fclose(pf);//关闭文件
pf = NULL;
return 0;
}
5.4 格式化读写函数
1. fprintf 格式化写入(类似 printf)
-
原型:
int fprintf(FILE *stream, const char *format, ...);//将格式化数据写入指定文件流的函数,与printf类似 可以输出到任意输出流
-
参数:
stream:文件指针 / 输出流format:格式字符串...:可变参数(待写入数据)
-
返回值:成功返回写入字符个数 ;失败返回负数
示例:写入结构体数据
cpp
//用fprintf写入文件
#include<stdio.h>
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = { "zhangsan", 20, 95.5f };
FILE* pf = fopen("test.tst", "w");//写文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
fprintf(pf,"名字:%s 年龄;%d 成绩:%f\n",s.name ,s.age,s.score );
fclose(pf);//关闭文件
pf = NULL;
return 0;
}

2. fscanf 格式化读取(类似 scanf)
-
原型:**int fscanf(FILE stream, const char format, ...)
;//从指定文件中读取格式化数据的函数 可以指定输入源 适用于从文件解析结构化数据 -
参数:
stream:文件指针 / 输入流format:格式控制字符串(同scanf)...:变量地址列表
-
返回值:
示例:读取文件中结构体数据
cpp
//用fscanf读取数据
#include<stdio.h>
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = { "zhangsan", 20, 95.5f };
FILE* pf = fopen("test.tst", "w");//写文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
fscanf(pf, "名字:%s 年龄:%d 成绩:%f", s.name, &(s.age), &(s.score));
fprintf(stdout, "名字:%s 年龄:%d 成绩:%.2f\n", s.name, s.age, s.score);
fclose(pf);//关闭文件
pf = NULL;
return 0;
}

5.5 sprintf 和 sscanf
1. sprintf
原型
int sprintf(char *str, const char *format, ...);
功能
把格式化数据写入字符数组(字符串) ,相当于把 printf 的输出从屏幕改成内存字符串。
参数
str:字符数组指针,存储生成的字符串 (空间要足够,防止溢出)format:格式字符串(**%d、%f、%s**等)...:可变参数,对应格式的数据
返回值
- 成功:返回写入的字符数 (不含末尾
\0) - 失败:返回负值
示例(核心就是把内容转换成字符串 并存放)
struct Stu s = {"zhangsan", 100, 85.5f};
char arr[100] = {0};
sprintf(arr, "%s %d %.1f", s.name, s.age, s.score);
2. sscanf
原型
int sscanf(const char *str, const char *format, ...);
功能
从字符串里读取格式化数据 ,相当于把 scanf 的输入从键盘改成内存字符串。
参数
str:源字符串(数据来源)format:格式字符串...:变量地址列表
返回值
- 成功:返回成功读取赋值的参数个数
- 失败 / 到末尾:返回
EOF(-1)
示例(核心是从字符串中解析出一个格式化的数据)
char str[] = "zhangsan 100 85.5";
struct Stu s = {0};
sscanf(str, "%s %d %f", s.name, &s.age, &s.score);
两个结合起来使用
cpp
//ssprintf
//把格式化数据 转换成字符串并存放在内存中
#include<stdio.h>
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = { "zhangsan", 20, 95.5f };
char arr1[30] = { 0 };
sprintf(arr1, "%s %d %.2f", s.name, s.age, s.score);//存放进字符串内存区
printf("%s\n", arr1);
//sscanf
//从arr1中解析处一个结构体数据
struct Stu t = { 0 };
sscanf(arr1, "%s %d %f", t.name, &(t.age), &(t.score));
sprintf(stdout, "%s %d %.2f", s.name, s.age, s.score);//存放进字符串内存区
return 0;
}

3. 6组格式化函数总对比(图片表格)
| 函数 | 作用 | 操作对象 |
|---|---|---|
scanf |
格式化输入 | 标准输入 stdin |
printf |
格式化输出 | 标准输出 stdout |
fscanf |
格式化输入 | 文件流 / stdin |
fprintf |
格式化输出 | 文件流 / stdout |
sprintf |
格式化输出 | 内存字符串 |
sscanf |
格式化输入 | 内存字符串 |
5.6 二进制批量读写函数
1. fwrite 二进制写入(把一个数据通过流传到文件中)
-
原型:size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream)
; -
参数
ptr:待写入数据的内存首地址size:单个数据的字节大小count:要写入的数据个数stream:文件指针
示例:写入数组二进制数据
cpp
//fwrite的使用
#include<stdio.h>
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = { "zhangsan", 20, 95.5f };
FILE* pf = fopen("test.tst", "wb");//写二进制文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写一个结构体类型的内容 到文件中去
fwrite(&s, sizeof(struct Stu), 1, pf);
fclose(pf);
pf = NULL;
return 0;
}

2. fread 二进制读取(从文件中读取数据到格式化变量中)
- 原型 :
size_t fread(**void ptr, size_t size, size_t count, FILE stream) - 功能:批量写二进制
- 参数:
const void* buf, size_t size, size_t count, FILE* stream - 返回:实际写入的块数
示例:读取二进制结构体数据
cpp
//fread读取二进制数据
#include<stdio.h>
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = { "zhangsan", 20, 95.5f };
FILE* pf = fopen("test.tst", "rb");//读取二进制文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读取文件中的数据
fread(&s, sizeof(struct Stu), 1, pf);
printf("%s %d %.2f\n", s.name, s.age, s.score);
fclose(pf);
pf = NULL;
return 0;
}

5.6 核心编码规范
- 打开文件必须判断
NULL,用perror("fopen")打印错误 - 文本模式:
r/w/a;二进制模式:rb/wb/ab - 用完必须
fclose(fp); fp=NULL; - 读取后用
feof、ferror判断状态
六、文件的随机读写
一、随机读写 3 个核心函数
1. fseek(移动文件指针)
- 原型 :
int fseek(FILE *stream, long int offset, int origin); - 功能 :定位文件指针 ,实现随机读写
- 参数
stream:文件指针offset:偏移量 (正数向后 、负数向前 、0 不动)origin:基准位置SEEK_SET:文件开头SEEK_CUR:当前指针位置SEEK_END:文件末尾
- 返回值 :成功返回
0;失败返回非 0(-1) - 注意 :二进制文件可随意偏移;文本文件仅支持
SEEK_SET或ftell返回值偏移
cpp
//用fseek定位文件指针实现随机打印
//文件中是 abcdefghi
#include<stdio.h>
int main()
{
FILE* fp = fopen("test.txt", "r");
if (fp == NULL)
{
perror("fopen");
return 1;
}
int c = fgetc(fp);//a
fputc(c, stdout);//使用fputc在标准输入流上打印字符
//定位文件指针
fseek(fp, 5, SEEK_SET);//从首个开始定位 向右5个偏移量
fseek(fp, 4, SEEK_CUR);//这是从a开始定位 向右4个偏移量
fseek(fp, -4, SEEK_END);//这是从末尾开始定位 向左4个偏移量
c = fgetc(fp);
fputc(c, stdout);//f
fclose(fp);
fp = NULL;
return 0;
}


2. ftell(获取当前指针偏移)
-
原型 :
long int ftell(FILE *stream); -
功能 :返回文件指针相对于文件开头的字节偏移量
-
参数 :
stream:文件指针 -
返回值 :成功返回字节数;失败返回
-1L -
用途 :常和
fseek配合,计算文件大小fseek(fp,0,SEEK_END); long size=ftell(fp); // 得到文件总字节大小
fseek和ftell的共同使用
cpp
//fseek和 ftell的共同使用
#include<stdio.h>
int main()
{
FILE* fp = fopen("test.txt", "r");
if (fp == NULL)
{
perror("fopen");
return 1;
}
int c = fgetc(fp);
fputc(c, stdout);//输出a
int pos = ftell(fp);//这里记录的是b相对于起始位置的偏移量1
//定位文件指针
fseek(fp, 4, SEEK_CUR);
c = fgetc(fp);
fputc(c, stdout);//这里的是f(相对b往后偏移4)
fseek(fp, pos, SEEK_SET);//这里回到初始 偏移量为1
c = fgetc(fp);
fputc(c, stdout);//这里就是b
fclose(fp);
fp = NULL;
return 0;
}


3. rewind(指针回到开头)
- 原型 :
void rewind(FILE *stream); - 功能 :文件指针重置到文件开头
- 关键区别
rewind(fp):移动指针 + 清除错误标志、文件末尾标志fseek(fp,0,SEEK_SET):只移动指针,不清除标志
cpp
接着上面的代码用rewind回到起始位置
fputc(c, stdout);//这里就是b
rewind(fp);//回到起始位置
c = fgetc(fp);
fputc(c, stdout);//这里就是a
fclose(fp);
fp = NULL;
return 0;

七、文件缓冲区
7.1 文件缓冲区概念
- ANSI C 规定:系统自动在内存给每个打开的文件开辟一块缓冲区
- 输出:程序数据 → 输出缓冲区 → 缓冲区满 / 刷新 → 写入硬盘
- 输入:硬盘数据 → 输入缓冲区 → 程序读取
- 作用:减少磁盘 IO,提升读写效率
7.2 fflush 函数(强制刷新缓冲区)
原型
int fflush(FILE *stream);
功能
- 输出流:强制把缓冲区数据立刻写入硬盘
- 输入流:行为不标准,一般不用
stream=NULL:刷新所有打开的输出流
参数
stream:文件指针 /stdout
返回值
- 成功:
0 - 失败:
EOF
刷新缓冲区的 4 种方式
- 缓冲区写满,自动刷新
- 调用
fflush(fp),手动强制刷新 - 调用
fclose(fp)关闭文件,自动刷新 - 程序正常结束,自动刷新
核心结论
文件操作必须刷新缓冲区或关闭文件,否则数据可能只在内存,没写到硬盘。
示例代码
FILE* pf = fopen("test.txt", "w");
fputs("abcdef", pf);
fflush(pf); // 强制写入磁盘
fclose(pf);