news 2026/7/13 10:57:16

C语言学习笔记20260712-文件操作核心函数详解与实例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C语言学习笔记20260712-文件操作核心函数详解与实例

C语言学习笔记20260712-文件操作核心函数详解与实例

在C语言中,程序运行时产生的数据默认存储在内存中,一旦程序退出,内存被系统回收,数据就会永久丢失。文件操作的核心价值在于将数据从内存写入硬盘,实现数据的“持久化存储”。C语言标准库(<stdio.h>)提供了一套强大的文件操作接口,下面将为你详细梳理核心函数、读写方式及易错点。

一、 文件的打开与关闭

文件操作的第一步是建立程序与硬盘文件的连接,使用完毕后必须断开连接。

1. fopen:打开文件

  • 原型:FILE *fopen(const char *filename, const char *mode);
  • 功能:打开指定路径的文件。FILE是一个结构体指针,包含了文件缓冲区、当前读写位置等信息,是操作文件的“身份证”。
  • 返回值:成功返回指向该文件的指针;失败返回NULL
  • 常用打开模式:
    • "r":只读打开文本文件(文件必须存在)。
    • "w":只写打开文本文件(若存在则清空内容,不存在则新建)。
    • "a":追加打开文本文件(写入的数据会附加在文件末尾)。
    • "rb"/"wb":以二进制模式只读/只写打开(适用于非字符数据,如图片、音频、结构体)。
    • "r+"/"w+"/"a+":以读写模式打开。

2. fclose:关闭文件

  • 原型:int fclose(FILE *stream);
  • 功能:关闭文件并刷新缓冲区,确保数据真正写入硬盘。
  • 返回值:成功返回 0,失败返回 EOF。
#include<stdio.h>#include<stdlib.h>intmain(){// 以只写模式打开(或新建)一个文本文件FILE*fp=fopen("test.txt","w");// 必须检查文件是否打开成功if(fp==NULL){perror("fopen failed");return1;}printf("文件打开成功,准备写入数据...\n");// 文件操作...// 使用完毕后必须关闭文件if(fclose(fp)!=0){perror("fclose failed");return1;}fp=NULL;// 防止悬空指针return0;}

二、 文件的顺序读写

顺序读写是指从文件开头按顺序一笔一笔地读取或写入数据,这是最常用的文件操作方式。

1. 字符读写:fgetc / fputc

适用于逐个字符处理文本,如统计字符数、过滤特定字符。

  • fgetc:从流中读取一个字符,成功返回字符的ASCII码,失败或读到文件尾返回EOF
  • fputc:向流中写入一个字符,成功返回该字符,失败返回EOF
// 示例:将用户输入的字符写入文件,直到输入 '$' 为止voidchar_io_example(){FILE*fp=fopen("char_test.txt","w");if(fp==NULL)return;charch;printf("请输入字符(输入$结束):");while((ch=getchar())!='$'){fputc(ch,fp);// 写入字符到文件}fclose(fp);}

2. 文本行读写:fgets / fputs

适用于按行处理文本,如读取配置文件、日志文件。

  • fgets:从流中读取一行(或指定大小)的字符串到缓冲区。遇到换行符\n或读取满n-1个字符时停止,并自动添加\0。成功返回缓冲区地址,失败或读到文件尾返回NULL
  • fputs:向流中写入一个字符串(不会自动添加换行符)。
// 示例:向文件写入一行文本,并重新读取出来voidstring_io_example(){FILE*fp=fopen("line_test.txt","w+");// 读写模式if(fp==NULL)return;constchar*str="Hello, C Language File!\n";fputs(str,fp);// 写入字符串rewind(fp);// 将文件指针重置到开头,准备读取charbuffer={0};if(fgets(buffer,sizeof(buffer),fp)!=NULL){printf("读取到的内容:%s",buffer);}fclose(fp);}

3. 格式化读写:fprintf / fscanf

适用于处理包含多种数据类型(如整数、浮点数、字符串)的结构化文本数据。

  • fprintf:将格式化数据写入文件(类似printf)。
  • fscanf:从文件中按格式读取数据(类似scanf)。
// 示例:保存和读取学生信息structStudent{charname;intage;floatscore;};voidformat_io_example(){structStudentstu={"Alice",20,95.5};FILE*fp=fopen("student.txt","w+");if(fp==NULL)return;// 格式化写入fprintf(fp,"%s %d %.1f",stu.name,stu.age,stu.score);rewind(fp);// 重置指针structStudentnew_stu;// 格式化读取fscanf(fp,"%s %d %f",new_stu.name,&new_stu.age,&new_stu.score);printf("姓名:%s, 年龄:%d, 分数:%.1f\n",new_stu.name,new_stu.age,new_stu.score);fclose(fp);}

4. 二进制读写:fread / fwrite

适用于高效存储结构体、数组等非字符数据。二进制文件将内存中的数据原封不动地保存,存取速度快,占用空间小。

  • fwrite:向文件写入二进制数据。
  • fread:从文件读取二进制数据。
// 示例:将结构体数组以二进制形式存入文件voidbinary_io_example(){structStudentclass_arr={{"Bob",21,88.0},{"Cathy",19,92.5}};// 使用 wb 二进制写模式FILE*fp=fopen("class.bin","wb");if(fp==NULL)return;// 写入:缓冲区首地址, 单个元素大小, 元素个数, 文件指针size_twritten=fwrite(class_arr,sizeof(structStudent),2,fp);printf("成功写入 %zu 条记录\n",written);fclose(fp);// 读取演示fp=fopen("class.bin","rb");structStudentread_arr;// 读取:返回实际成功读取的元素个数size_tread_count=fread(read_arr,sizeof(structStudent),2,fp);for(size_ti=0;i<read_count;i++){printf("二进制读取 - 姓名:%s\n",read_arr[i].name);}fclose(fp);}

三、 文件的随机读写

有时我们需要跳过文件中间的部分,直接读取或修改特定位置的数据,这时需要使用定位函数。

  • fseek:重定位文件指针。fseek(fp, offset, whence)whence可以是SEEK_SET(文件开头)、SEEK_CUR(当前位置)、SEEK_END(文件末尾)。
  • ftell:返回当前文件指针相对于文件开头的偏移量(字节数)。
  • rewind:将文件指针重置到文件开头(等价于fseek(fp, 0, SEEK_SET))。
// 示例:修改文件中特定位置的数据voidrandom_access_example(){FILE*fp=fopen("data.txt","w+");if(fp==NULL)return;fputs("Hello World",fp);// 将指针移动到第6个字节处(即 'W' 的位置)fseek(fp,6,SEEK_SET);fputs("C",fp);// 将 'W' 替换为 'C'rewind(fp);// 回到开头charbuf;fgets(buf,sizeof(buf),fp);printf("修改后的内容:%s\n",buf);// 输出: Hello Corldfclose(fp);}

四、 核心易错点与避坑指南

1. 文件读取结束的正确判定

致命误区:绝不能直接用feof()的返回值作为循环条件来判断文件是否结束!feof只有在“读取失败后”才能准确判断是否是因为遇到了文件尾。

  • 文本文件:循环条件应判断fgetc() != EOFfgets() != NULL。循环结束后,再用feof()ferror()判断是正常读完还是出错。
  • 二进制文件:循环条件应判断fread的返回值是否小于实际要读的个数。
// 文本文件读取的正确姿势intc;while((c=fgetc(fp))!=EOF){putchar(c);}// 循环结束后判断原因if(ferror(fp)){puts("读取过程中发生IO错误");}elseif(feof(fp)){puts("文件正常读取完毕");}

2. 文件缓冲区机制

C语言文件操作默认带有缓冲区(全缓冲)。调用fprintffwrite时,数据可能只是暂时存放在内存的缓冲区中,并未立刻写入硬盘。

  • 刷新缓冲区:调用fclose()关闭文件时会自动刷新;或者手动调用fflush(fp)强制将缓冲区数据写入硬盘。
  • 风险:如果程序异常崩溃(如被kill -9强杀)而未执行fclose,缓冲区内的数据将会丢失。

3. 标准I/O与系统I/O的区别

  • 标准I/O (fopen/fread等):跨平台(Windows/Linux通用),自带缓冲区,效率高,基于FILE*指针。
  • 系统I/O (open/read/write等):仅限Linux/Unix,无缓冲区(直接系统调用),基于文件描述符(整数int fd),常用于设备文件驱动开发。日常应用开发推荐优先使用标准I/O。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/13 10:57:01

5个可嵌入日常对话的心理学微行为脚本

1. 项目概述&#xff1a;这不是一个“插件”&#xff0c;而是一套可嵌入日常沟通的微行为系统 “Superpowers插件的心理学技巧”——光看标题&#xff0c;很多人第一反应是&#xff1a;“这是不是某个浏览器插件&#xff1f;或者AI工具的增强包&#xff1f;”其实完全不是。我在…

作者头像 李华
网站建设 2026/7/13 10:56:03

A3908直流电机驱动器与PIC18LF46K80的运动控制方案解析

1. A3908直流电机驱动器核心特性解析A3908是Allegro MicroSystems推出的一款专为低压场景优化的直流电机驱动器IC&#xff0c;其设计理念聚焦于在3-5.5V电压范围内实现精确的电机控制。这款芯片采用全桥式输出架构&#xff0c;集成了源端线性调节功能&#xff0c;能够为电机线圈…

作者头像 李华
网站建设 2026/7/13 10:55:36

TS2007FC与PIC18F86K22在嵌入式音频系统中的应用与优化

1. 为什么选择TS2007FC与PIC18F86K22这对黄金组合 在嵌入式音频系统设计中&#xff0c;芯片选型往往决定了最终音质表现的上限。TS2007FC作为意法半导体推出的3W无滤波D类音频功率放大器&#xff0c;与Microchip的PIC18F86K22单片机搭配&#xff0c;形成了一个兼顾性能与成本的…

作者头像 李华
网站建设 2026/7/13 10:55:30

AI算力狂飙,液冷板焊缝为什么不能有一丝泄漏?

所谓液冷板的激光封焊&#xff0c;就是用激光束将上下两块金属板沿微通道边缘逐条熔合&#xff0c;形成一道必须经受10⁻⁹级别气密性考验的密封焊缝——任何一处未熔合、任何一粒微米级气孔&#xff0c;都意味着冷却液将在未来某个时刻渗入算力芯片的核心区域。2026年7月&…

作者头像 李华
网站建设 2026/7/13 10:55:10

Godot场景节点选择与对齐全攻略:告别叠罗汉,实现精准操控

1. 项目概述&#xff1a;从“叠罗汉”到精准操控的进化 在Godot引擎里摸爬滚打这些年&#xff0c;我见过太多新手开发者&#xff08;甚至一些老手&#xff09;在场景编辑器里“叠罗汉”——把节点一个个拖进去&#xff0c;然后凭感觉手动调整位置&#xff0c;试图让它们对齐。结…

作者头像 李华
网站建设 2026/7/13 10:54:18

ComfyUI-VideoHelperSuite:构建AI视频工作流的技术架构与工程实践

ComfyUI-VideoHelperSuite&#xff1a;构建AI视频工作流的技术架构与工程实践 【免费下载链接】ComfyUI-VideoHelperSuite Nodes related to video workflows 项目地址: https://gitcode.com/gh_mirrors/co/ComfyUI-VideoHelperSuite 项目定位与技术栈解析 ComfyUI-Vid…

作者头像 李华