C语言学习:文件操作

一、文件的作用

文件的核心作用就是:把数据从易失的内存,存到持久的硬盘里,程序退出了数据也不会丢。

二、文件是什么?

在 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 的两种存储

  1. 内存中的形式 10000 作为 int 类型,在内存中是 4 字节的二进制:00000000 00000000 00100111 00010000(十进制转二进制结果)。

  2. ASCII 形式(文本文件) 会把 10000 拆成 5 个字符:'1' '0' '0' '0' '0',每个字符的 ASCII 码是:

    • '1'00110001(49)
    • '0'00110000(48) 所以文件里会存这 5 个字节:00110001 00110000 00110000 00110000 00110000共 5 字节。
  3. 二进制形式(二进制文件) 直接把内存中的 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 中查看二进制文件的方法

  1. 在 VS 的「解决方案资源管理器」中,右键 test.txt
  2. 选择「打开方式」。
  3. 在弹出的窗口中,选择「二进制编辑器」
  4. 打开后就能看到文件的十六进制内容: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 文件的打开与关闭:fopenfclose

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 避坑指南与关键细节

  1. 必须判空fopen 失败会返回 NULL,如果直接使用空指针操作文件,会导致程序崩溃。
  2. 关闭文件:不关闭文件会导致缓冲区数据未写入硬盘,文件内容丢失;同时占用系统资源。
  3. 文本 vs 二进制模式
    • 文本模式下,Windows 系统会自动将 \n 转换为 \r\n 写入文件,读取时再转换回来。
    • 二进制模式下,数据原封不动读写,不会做任何转换,适合图片、视频等非文本数据。
  4. 路径问题 :Windows 下路径分隔符是 \,但 C 语言中 \ 是转义字符,所以路径要写成 D:\\test.txtD:/test.txt
  5. "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 核心编码规范

  1. 打开文件必须判断NULL,用perror("fopen")打印错误
  2. 文本模式:r/w/a;二进制模式:rb/wb/ab
  3. 用完必须fclose(fp); fp=NULL;
  4. 读取后用feofferror判断状态

六、文件的随机读写

一、随机读写 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_SETftell返回值偏移
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 种方式

  1. 缓冲区写满,自动刷新
  2. 调用 fflush(fp)手动强制刷新
  3. 调用 fclose(fp) 关闭文件,自动刷新
  4. 程序正常结束,自动刷新

核心结论

文件操作必须刷新缓冲区或关闭文件,否则数据可能只在内存,没写到硬盘。

示例代码

复制代码
FILE* pf = fopen("test.txt", "w");
fputs("abcdef", pf);
fflush(pf);  // 强制写入磁盘
fclose(pf);
相关推荐
AI算法沐枫3 小时前
大模型 | 大模型之机器学习基本理论
人工智能·python·神经网络·学习·算法·机器学习·计算机视觉
小新同学^O^4 小时前
简单学习 --> LangChain
python·学习·langchain
吃好睡好便好5 小时前
在Matlab中绘制阶梯图
开发语言·人工智能·学习·算法·机器学习·matlab
Restart-AHTCM5 小时前
LangChain学习之提示词模板 (Prompts) - 练习(2/8)
学习·langchain
YangYang9YangYan5 小时前
2026产品专员学习数据分析的价值与路径
学习·数据挖掘·数据分析
淘矿人5 小时前
【AI大模型】AI 大模型推理平台完整测评:8 家主流聚合服务对比分析
人工智能·sql·gpt·学习·github·php
我想我不够好。6 小时前
2026.5.20 消防监控学习 1.5hour
学习
爱喝水的鱼丶6 小时前
SAP-ABAP:数据类型与数据对象(8篇) 第七篇:进阶优化篇——基于类型与对象特征的性能优化技巧
运维·数据库·学习·性能优化·sap·abap·开发交流
知识分享小能手7 小时前
Flask入门学习教程,从入门到精通, 认识Flask路由 — 知识点详解 (2)
python·学习·flask