文件读写操作与易错点总结

个人主页流年如夢

专栏《C语言》

文章目录

Ladies and gentlemen,本篇文章讲的是文件操作,下面将带领大家学习 文件打开关闭(fopen、fclose)、顺序读写、随机读写、结束判定、文件缓冲区、更新文件 等;全程高能,不容错过!!!

前言

程序运行时的数据都存放在内存中,程序退出后数据就会丢失。如果想让数据持久化保存,就必须用到文件操作。C语言提供了完整的文件读写接口,支持文本和二进制两种存储格式,能实现数据的写入、读取、修改、追加等功能。本篇文章带你从零掌握文件操作,写出稳定、安全、规范的文件处理代码。

一.了解文件

1.1为什么需要使用文件

因为程序退出后,内存数据会被回收 ,数据无法保存;但使用文件可以把数据存放在硬盘 中,实现数据持久化;在下次运行程序时,可以从文件中读取历史数据。

1.2什么是文件

磁盘上的文件就是文件,例如我们电脑都有的C盘和D盘

当然,在程序设计中分为两类:程序文件和数据文件

程序文件

  1. 源文件(.c
  2. 目标文件(.obj
  3. 可执行程序(.exe

数据文件(本篇重点)

程序运行时用于读写数据的文件

文件名

文件名 = 文件路径 + 文件名主干 + 后缀

c 复制代码
例如:c:\code\test.txt

二.二进制文件和文本文件

2.1文本文件

ASCII字符形式存储,可以直接看懂的

2.2二进制文件

以内存二进制形式存储,节省空间、读写快

举个例子:

c 复制代码
#include <stdio.h>

int main()
{
    int a = 10000;
    FILE* pf = fopen("test.txt", "wb");
    fwrite(&a, 4, 1, pf);
    fclose(pf);
    pf = NULL;

    return 0;
}

分析wb是以二进制只写方式打开;fwrite是按二进制写入,int只占4字节

运行结果:

在这里程序没有报错,说明运行成功 ;这时双击左上角打开文件test.txt(或ctrl+c),我们可以看到10000二进制方式 写入文件,如下所示:

三.文件的打开(fpoen)和关闭(fclose)

3.1流和标准流

流(stream):数据传输的抽象,可理解为 "数据的河流"

三个默认标准流

  1. stdin --> 标准输入(用键盘)
  2. stdout --> 标准输出(在屏幕上)
  3. stderr --> 标准错误

3.2文件指针

每个打开的文件,系统都会创建一个FILE结构体信息区,我们用FILE*指针来操作文件

3.3fopen --> 打开文件

函数原型

c 复制代码
FILE* fopen(const char* filename, const char* mode);

其中打开失败返回NULL ,必须判断;mode是打开方式(例如r、w、a、rb、wb、ab、r+、w+、a+...

3.4fclose -- > 关闭文件

函数原型

c 复制代码
int fclose(FILE* stream);

使用fclose关闭文件,并刷新缓冲区 ;关闭后必须把指针置 NULL

3.5举例

c 复制代码
#include <stdio.h>

int main()
{
    FILE* fp = fopen("test.txt", "r");//这里先打开文件
    if (fp == NULL)
    {
        perror("fopen");
        return 1;
    }

    // 读写操作...

    fclose(fp);//最后关闭文件
    fp = NULL;

    return 0;
}

🧐分析 :先打开判断、用完关闭、最后指针置空;perror是用来直接打印错误原因,方便调试

四.文件的顺序读写(cplusplus链接👈)

表格

函数 功能 适用
fputc 写一个字符 所有输出流
fgetc 读一个字符 所有输入流
fputs 写一行字符串 所有输出流
fgets 读一行字符串 所有输入流
fprintf 格式化写入 所有输出流
fscanf 格式化读取 所有输入流
fwrite 二进制块写入 文件流
fread 二进制块读取 文件流

4.1fputc与fgetc

4.1.1函数原型

功能:向指定流中写入一个字符 ,写完后文件指针自动后移

参数:character是要写入的字符;stream是目标文件流

返回值:成功返回写入的字符,失败返回EOF

功能:从指定流中读取一个字符,读完后文件指针自动后移

参数:stream是要读取的文件流

返回值:成功返回读到的字符,读到末尾或出错返回EOF

4.1.2举例

c 复制代码
//写入
fputc('a', fp);
//读取
int ch = fgetc(fp);

4.2fputs与fgets

4.2.1函数原型

功能:向文件中写入一个字符串 ,不写入末尾\0

参数:str是要写入的字符串;stream是目标文件流

返回值:成功返回非负数,失败返回EOF

功能:从文件中读取一行或指定长度字符串

参数:str是存放读取内容;num是最多读num-1个字符;stream是文件流

返回值:成功返回str,失败或到末尾返回NULL

4.2.2举例

c 复制代码
fputs("hello world", fp);

char buf[100] = {0};
fgets(buf, 100, fp);

4.3fprintf与fscanf

4.3.1函数原型

功能:格式化写入 文件,用法和printf几乎一样

参数:stream是目标流;format是格式化字符串;后续为输出参数

返回值:成功返回写入字符数,失败返回负数

功能:格式化读取 文件内容,用法和scanf类似

参数:stream是输入流;format是格式串;后续为地址参数

返回值:成功返回读取参数个数,失败或到末尾返回EOF

4.3.2举例

c 复制代码
struct Stu
{
    char name[20];
    int age;
};

//写入
fprintf(fp, "%s %d", s.name, s.age);
//读取
fscanf(fp, "%s %d", s.name, &s.age);//数组name本身就是指针,不需要 &

4.4fwrite与fread

4.41函数原型

功能:以二进制形式 整块写入文件

参数:ptr是数据地址;size是一个元素大小;count是元素个数;stream是文件流

返回值:成功写入的元素个数

功能:以二进制形式 从文件整块读取数据

参数:ptr是接收数据的缓冲区;size是一个元素大小;count是要读个数;stream是文件流

返回值:实际读到的元素个数

4.4.2举例

c 复制代码
//写入
fwrite(&s, sizeof(struct Stu), 1, fp);
//读取
fread(&s, sizeof(struct Stu), 1, fp);

4.5三组函数对比

函数 功能
scanf 从标准输入读
fscanf 任意流
sscanf 字符串
printf 打印到标准输出
fprintf 打印到任意流
sprintf 打印到字符串

五.文件的随机读写

5.1fseek --> 定位文件指针

函数原型:

SEEK_SET --> 文件开头

SEEK_CUR --> 当前位置

SEEK_END --> 文件末尾

例如:

c 复制代码
fseek(fp, offset, origin);

5.2ftell --> 获取当前偏移

函数原型:

功能:返回当前文件指针相对于开头的偏移量

例如:

c 复制代码
long pos = ftell(fp);

5.3rewind --> 回到文件开头

函数原型:

功能:把文件指针重置到文件开头

例如:

c 复制代码
rewind(fp);

六.文件读取结束的判定(feof与ferror)

6.1feof

判断是否是正常读到文件末尾

c 复制代码
if (feof(fp))
    printf("读到文件末尾\n");

6.2ferror

判断是否是发生读取错误

c 复制代码
if (ferror(fp))
    printf("读取出错\n");

注意:feof不是用来判断是否结束,而是结束后判断是 "读到尾" 还是 "出错"

七.文件缓冲区

系统会为每个文件自动开辟缓冲区 ;数据先写缓冲区,满了或刷新才写入磁盘;fflush(fp)会强制刷新缓冲区

c 复制代码
fputs("abc", fp);
fflush(fp);//立即写入磁盘

八.更新文件(r+、w+、a+)

模式 文件不存在 原有内容 指针位置
r+ 打开失败 保留 开头
w+ 创建新文件 清空 开头
a+ 创建新文件 保留 末尾

规则

写完读:必须fflushfseek

读完写:必须fseekrewind

🎯总结

  1. 文件用于数据持久化,分为文本文件和二进制文件
  2. 操作流程为 fopen --> 读写 --> fclose --> 置空(NULL
  3. 打开文件必须判断是否为NULL
  4. 顺序读写fgetcfputcfgetsfputsfprintffscanf
  5. 二进制读写有freadfwrite
  6. 随机读写fseekftellrewind
  7. 结束判定 时要用feofferror区分结束原因
  8. 缓冲区fflush强制刷新,fclose自动刷新
  9. 更新模式读写切换必须刷新或重定位

⚠️易错点

  1. 不判断fopen返回值,直接使用空指针
  2. 忘记fclose,导致数据丢失、文件占用
  3. fclose后不置空,形成野指针
  4. 混淆文本方式与二进制方式
  5. fgets读取时包含\n,处理不当出错
  6. 读写切换不刷新、不定位,导致读写异常
  7. feof提前判断循环结束,逻辑错误

👀 关注 我们一路同行,从入门到大师,慢慢沉淀、稳步成长
❤️ 点赞 鼓励原创,让优质内容被更多人看见
⭐ 收藏 收好核心知识点与实战技巧,需要时随时查阅
💬 评论 分享你的疑问或踩坑经历,一起交流避坑、共同进步

相关推荐
c++圈来了个新人2 小时前
C++类和对象(中)
c语言·开发语言·数据结构·c++·考研·算法
bucenggaibian2 小时前
C语言如何直接控制硬件?指针、内存与寄存器
c语言·内存·指针·寄存器·硬件控制
2401_892070982 小时前
红黑树(RBTree):原理 + 5 大性质 + 旋转 + 插入 + 删除 + 完整工程级代码逐行解析
c语言·数据结构·红黑树
Lazionr2 小时前
【链表经典OJ-下】
c语言·数据结构·链表
CPUOS20102 小时前
嵌入式C语言高级编程之接口隔离原则
c语言·网络·接口隔离原则
sghuter2 小时前
HTML头部元信息避坑指南
c语言·前端·html·cocoa
光电笑映2 小时前
Linux C/C++ 开发工具(下):make/Makefile、进度条小程序与 gdb 调试器
linux·c语言·c++
71-32 小时前
C语言练习——数组的练习(涉及顺序、二分查找,冒泡排序)
c语言·笔记·学习·排序算法·查找算法