八种顺序读写函数
目录摘要一文件操作的流程1fopen2fclose3文件的路径4顺序和随机的区别5默认流二顺序读写函数1fputc2fgetc3fputs4fgets5fprintf6fscanf7fwite8fread摘要本博客介绍并使用8种顺序读写函数~一文件操作的流程读写的含义读读出即从文件里面读出数据-----------和scanf从键盘里面读出数据类似写写入即把数据写入文件里面-----------和printf把数据写入到屏幕上类似想对文件进行读写操作则流程一定为打开文件---读/写文件---关闭文件而我们对文件可能是只读可能是只写可能是追加可能是既读又写所以在使用fopen打开文件的时候函数规定需要在fopen的对应参数选择对应的打开模式~1fopenFILE * fopen ( const char * filename, const char * mode )参数解释参数类型说明filenameconst char *要打开的文件名可包含路径modeconst char *打开模式函数作用建立调用fopen的程序与filename文件之间的连接返回一个FILE *类型的指针供后续读写操作使用返回值成功返回FILE *失败返回NULL注意事项返回值为FILE*是结构体FILE的指针通过该指针可以进行文件的相关操作必须检查返回值后序读写前务必先判断fopen的返回值是否为NULL常用的打开模式如下文件使用方式含义如果指定文件不存在“r” (只读)为了输入数据打开一个已经存在的文本文件出错“w” (只写)为了输出数据打开一个文本文件建立一个新的文件“a” (追加)向文本文件尾添加数据建立一个新的文件“rb” (只读)为了输入数据打开一个二进制文件出错“wb” (只写)为了输出数据打开一个二进制文件建立一个新的文件“ab” (追加)向一个二进制文件尾添加数据建立一个新的文件“r” (读写)为了读和写打开一个文本文件出错“w” (读写)为了读和写建议一个新的文件建立一个新的文件“a” (读写)打开一个文件在文件尾进行读写建立一个新的文件“rb” (读写)为了读和写打开一个二进制文件出错“wb” (读写)为了读和写新建一个新的二进制文件建立一个新的文件“ab” (读写)打开一个二进制文件在文件尾进行读和写建立一个新的文件2fcloseint fclose ( FILE * stream );参数解释参数类型说明streamFILE *参数就是fopen的返回值函数作用关闭文件并且断开程序与文件之间的连接(顺便会刷新缓冲区)返回值返回值含义0关闭成功EOF通常是 -1关闭失败如缓冲区刷新失败、无效流指针等注意事项fclose关闭文件后安全起见必须将 FILE * 类型的fp设为 NULL但由于fclose一般都是代码的末尾执行后面也不会在使用fp所以往往会省去这一步但加上才是更优秀的做法所以文件操作的整体框架就为#include stdio.h int main() { //打开⽂件 FILE* pFile fopen(myfile.txt, w); //根据需求 进行⽂件读/写操作 //关闭文件 fclose(pFile); return 0; }3文件的路径在调用fopen时可以直接在第一个参数中传入文件名如data.txt此时系统会自动在当前工作目录下查找或创建该文件。当然也可以传入完整的绝对路径C:\\project\\data.txt来指定任意目录位置下的文件。某些打开模式是要求在指定路径下必须存在目标文件的所以当使用这些打开模式之前需要事先手动新建目标文件或者使用能够自动新建的写函数去创建文件而有些打开模式发现目录不存在会自动创建文件~4顺序和随机的区别顺序读写函数和随机读写函数都是因为存在文件位置指示器这个东西每次打开一个文件其对应的FILE结构体中就会维护着一个文件位置指示器也叫文件指针、文件偏移量它记录着下一次读写操作将从文件的哪个字节位置开始每次使用顺序读写函数后文件位置指示器会自动向后移动相应字节数因此读写操作会自然地形成顺序去进行读写而随机读写函数其可以修改文件位置指示器的值可以跳跃到文件的任意位置进行读写而不必按照顺序一个个处理所以叫做随机读写函数5默认流❓️那为什么scanf,printf的时候直接使用就行了不需要打开什么因为c语言程序只要运行起来就会默认打开3个流①标准输入流 stdin②标准输出流 stdout③标准错误流 stderr三个流的类型依然是 FILE*和读写函数的参数一致也可以理解为这一步电脑帮你省略了。都是与FILE * stream流有关流是什么流可以是文件从流里面读出数据写入数据到流里面只是不同的读写函数去读写的数据不一样一些是把单个字符写入到流或从流里读出单个字符一些是字符串的读写一些是二进制的读写二顺序读写函数顺序读写函数有8种如下函数名功能适用于fgetc字符输入函数所有输入流fputc字符输出函数所有输出流fgets文本行输入函数所有输入流fputs文本行输出函数所有输出流fscanf格式化输入函数所有输入流fprintf格式化输出函数所有输出流fread二进制输入文件fwrite二进制输出文件解释上⾯说的适用于所有输入流⼀般指适用于标准输⼊流和其他输⼊流如文件输⼊流所有输出流⼀般指适用于标准输出流和其他输出流如文件输出流⚠️此篇博客都是对当前路径下的test.txt文件进行操作所以前后会有因果关系1fputcint fputc ( int character, FILE * stream );参数解释参数类型说明characterint要写入的字符的ascll码值streamFILE *指向要写入的文件流的指针注character也可以直接传递a这种字符因为字符的本质就是ascll码值(int类型)函数作用将字符写入到文件中成功写入后文件位置指示器自动向后移动一个字节返回值返回值含义int (写入的字符的ascll码值)写入成功EOF-1写入失败读取时到达文件尾或发生错误注意事项fputc作为写函数自然需要以写相关的打开模式去打开文件使用示例a写入单个字符#include stdio.h int main() { FILE* fp fopen(test.txt, w); if (fp NULL) { perror(打开文件失败); return 1; } fputc(A, fp); fclose(fp); return 0; }解释test.txt文件不存在所以fopen以写的形式打开文件的时候会先在指定路径下新建该文件这里的路径只有文件名字所以默认路径就是当前程序对应的目录文件如下b循环写入字符解释因为是w模式打开文件而不是追加模式所以下一次的写之前会清空上一次所写的内容2fgetcint fgetc ( FILE * stream );参数解释参数类型说明streamFILE *指向要读取的文件的FILE结构体函数作用从指定的文件流stream中读取一个字符返回值返回该字符的 ASCII 值。如果读取时到达文件尾或发生错误则返回EOFEnd Of File一个特殊的常量通常在大多数系统中定义为 -1注意事项会读取包括空格、换行在内的所有字符使用示例①读取单个字符#include stdio.h int main() { FILE* fp fopen(test.txt, r); if (fp NULL) { perror(打开文件失败); return 1; } int ch fgetc(fp); if (ch ! EOF) { printf(读取到的字符%c\n, ch); } fclose(fp); return 0; }②循环读取字符#include stdio.h int main() { FILE* fp fopen(test.txt, r); if (fp NULL) { perror(打开文件失败); return 1; } int ch; while ((ch fgetc(fp)) ! EOF) { putchar(ch); } fclose(fp); return 0; }解释fgetc无法读取时返回值为EOF所以当我们想循环读取文件的时候就可以使用返回值不为EOF进行判断从而循环地去读完整个文件3fputsint fputs ( const char * str, FILE * stream );参数解释参数类型说明strconst char *要写入的字符串以\0结尾streamFILE *指向要写入的文件流的指针函数作用将字符串写入到指定的文件流中将字符串str写入到文件流stream中且文件位置指示器会向后移动写入的字节数返回值返回值含义 0写入成功返回最后一个写入的非负字符数EOF-1写入失败注意事项fputs不会自动添加换行需要换行要手动加\n(否则两次fputs会出现在同一行)字符串必须以\0结尾否则fputs会一直找字符串中的\0可能会导致越界访问使用示例#include stdio.h int main() { FILE* fp fopen(test.txt, w); if (fp NULL) { perror(打开文件失败); return 1; } fputs(hello world, fp); fclose(fp); return 0; }解释写入了一个字符串因为是w方式打开文件所以之间的文件内容会被清空再写入4fgetschar * fgets ( char *str, int num, FILE * stream );参数解释参数类型说明strchar *字符串的指针该字符串用于存储读取到的字符串numint最多读取的字符个数包含结尾的\0streamFILE *指向要读取的文件流的指针函数作用从文件流stream中读取一个最大字符数为num-1的字符串str返回值返回值含义str传入的指针str读取成功NULL到达文件末尾或发生读取错误注意事项num参数包含了结尾的\0所以实际最多读num-1个字符缓冲区str要足够大至少num字节fgets停止读取的三种情况情况说明① 遇到换行符\n读取换行符将\n存入str然后停止末尾加\0② 已读取num-1个字符还没遇到换行符停止末尾加\0③ 遇到文件尾 EOF没有读到任何字符返回NULL如果读到部分字符后遇到 EOF也会停止并加\0❓️如果fgets读取的时候遇到了\0呢会提前停止吗不会fgets是把\0当作普通数据字符读取不会因为读到\0就停止验证示例我们往文件中写入字符A \0 B \n C然后再用fgets读取10个字节❓️为什么不用fputs直接写入字符串A\0B\nC因为fputs写入的时候遇到\0就会停止不再往后写入这是特性否则fputs停不下来#include stdio.h int main() { // 用 fputs 写入但 fputs 遇到 \0 会停止写入 FILE* fp fopen(test.txt, w); fputs(A, fp); fputc(\0, fp); // 手动写入 \0 fputs(B\nC, fp); fclose(fp); // 用 fgets 读取 fp fopen(test.txt, r); char buf[100] { 0 }; fgets(buf, 100, fp); for (int i 0; i 10; i) { printf(buf[%d] %d\n, i, buf[i]); } fclose(fp); return 0; }解释数组下标十进制值对应字符说明buf[0]65A从文件读取的第一个字符buf[1]0\0从文件读取的空字符fprintf写入的%cbuf[2]66B\0后面的B说明遇到\0没停止buf[3]10\n换行符遇到它fgets才停止读取buf[4]0\0fgets自动添加的字符串结束符buf[5~9]0\0缓冲区剩余空间被初始化为 0未使用部分这代表遇到第一个\0没有停止下来而遇到\n换行符才会停止❓️为什么要这么设置因为文本文件中压根就没有\0你在记事本中见过\0吗但是存在换行所以检测\n5fprintfint fprintf ( FILE * stream, const char * format, ... );参数解释参数类型说明streamFILE *指向要写入的文件流的指针formatconst char *格式控制字符串包含格式占位符如%d、%s等...可变参数对应格式占位符要输出的变量函数作用将格式化的数据写入到指定的文件流中返回值返回值含义 0成功写入的字符总数负数写入失败注意事项格式字符串与变量类型要匹配否则结果不可预料使用示例#include stdio.h int main() { FILE* fp fopen(test.txt, w); if (fp NULL) { perror(打开文件失败); return 1; } int age 25; float score 92.5; char name[] 张三; fprintf(fp, %s\n, name); fprintf(fp, %d\n, age); fprintf(fp, %.1f\n, score); //合成一行的写法 //fprintf(fp, %s %d %.1f\n, name, age, score); fclose(fp); fp NULL return 0; }解释说白了就是在printf的用法上增加一个FILE*类型的参数fp而已6fscanfint fscanf ( FILE * stream, const char * format, ... );参数解释参数类型说明streamFILE *指向要读取的文件流的指针formatconst char *格式控制字符串指定如何解析数据...可变参数对应格式占位符的变量地址用于存储读取的值函数作用从文件中读取格式化的数据返回值返回值含义正整数成功匹配并赋值的参数个数0没有匹配到任何数据但可能有字符被读取EOF-1读取时到达文件尾或发生错误注意事项功能与scanf完全相同区别是scanf从键盘读取fscanf从文件读取自动跳过空白字符空格、换行、制表符等遇到类型不匹配或文件尾时停止使用示例#include stdio.h int main() { FILE* fp fopen(test.txt, r); if (fp NULL) { perror(打开文件失败); return 1; } char name[50]; int age; float score; fscanf(fp, %s, name); fscanf(fp, %d, age); fscanf(fp, %f, score); printf(%s\n, name); printf(%d\n, age); printf(%.1f\n, score); fclose(fp); return 0; }解释说白了就是在scanf的用法上增加一个FILE*类型的参数fp而已7fwitesize_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );参数解释参数类型说明ptrconst void *指向要写入的数据的指针sizesize_t每个元素的大小字节数countsize_t要写入的元素个数streamFILE *指向要写入的文件流的指针函数作用将数据块以二进制的形式写入文件流fwrite从由ptr指向的内存块中取出count个元素每个元素的大小为size字节并将它们写入到stream指向的文件流中返回值返回值含义count成功写入的元素个数等于count表示全部成功 count部分写入成功通常表示磁盘满或发生错误注意事项文件通常以二进制模式打开wb、ab、wb写入的是原始二进制数据用记事本打开可能显示乱码返回的是元素个数不是字节数实际字节数 返回值 × size适合配合fread使用使用示例#include stdio.h int main() { FILE *fp fopen(test.txt, wb); if (fp NULL) { perror(打开文件失败); return 1; } int arr[] {10, 20, 30, 40, 50}; fwrite(arr, sizeof(int), 5, fp); fclose(fp); return 0; }解释fwrite以二进制的形式向test.txt文件中写入数据后我们此时打开test.txt文件就是乱码8freadsize_t fread ( void * ptr, size_t size, size_t count, FILE * stream );参数解释参数类型说明ptrvoid *指向存储读取数据的缓冲区的指针sizesize_t每个元素的大小字节数countsize_t要读取的元素个数streamFILE *指向要读取的文件流的指针函数作用从文件中以二进制形式读取数据到内存中适合读取数组、结构体等二进制数据文件位置指示器向后移动size × 实际读取的元素个数字节返回值返回值含义count成功读取的元素个数等于count表示全部成功 count部分读取成功可能到达文件尾或发生错误0没有读取到任何元素文件尾或错误注意事项文件通常以二进制模式打开rb、ab、rb读取的是原始二进制数据必须与写入时的格式完全一致缓冲区ptr必须足够大至少size × count字节适合配合fwrite使用使用示例#include stdio.h int main() { // 先写入数据 FILE* fp fopen(test.txt, wb); int arr1[] { 10, 20, 30, 40, 50 }; fwrite(arr1, sizeof(int), 5, fp); fclose(fp); // 再读取数据 fp fopen(test.txt, rb); int arr2[5]; fread(arr2, sizeof(int), 5, fp); for (int i 0; i 5; i) { printf(%d , arr2[i]); } fclose(fp); return 0; } [ 作者 ] shylyly [ 首次发布 ] 2024.3.28❌ [ 最新修改 ] 2026.10.14 [ 声明 ] 由于笔者水平有限文中难免有疏漏或不妥之处还望读者不吝赐教

相关新闻

智能AI雷达名片系统设计拆解:招商获客与多租户SAAS实战

智能AI雷达名片系统设计拆解:招商获客与多租户SAAS实战

做了这么多年招商获客相关的工作,我最强烈的感受是:企业根本不缺产品、不缺优惠政策,缺的是第一时间知道“谁在看我们”。传统招商就像在广场上撒传单,传单发完了,谁捡起来看了、看的那个人是什么来头,一概…

2026/10/15 5:34:21 阅读更多 →
Rust RFC 1649 深度解读:原子类型的内存布局保证与 get_mut / into_inner 直接访问方法

Rust RFC 1649 深度解读:原子类型的内存布局保证与 get_mut / into_inner 直接访问方法

文档 【免费下载链接】rfcs RFCs for changes to Rust 项目地址: https://gitcode.com/gh_mirrors/rf/rfcs 点击查看 免费下载 导读 本文围绕 Rust 官方 RFC 仓库(rust-lang/rfcs)中的 RFC 1649:atomic_access 展开,…

2026/10/15 5:34:21 阅读更多 →
从72pt到2000pt:超大字号渲染的自研实践

从72pt到2000pt:超大字号渲染的自研实践

前段时间我给家里长辈配了一台电脑,顺便接了个需求:字要大,越大越好。老人视力下降,普通 12pt、14pt 的正文根本看不清,我的想法很简单——找一款软件,把字号拉到最大,最好一屏只显示一句话。结…

2026/10/15 5:33:21 阅读更多 →

最新新闻

SpringBoot+Vue轻量级博客系统设计与实现

SpringBoot+Vue轻量级博客系统设计与实现

1. 项目概述:SpringBootVue轻量级博客系统设计去年帮学弟评审毕业设计时,发现市面上很多博客系统要么功能冗余,要么扩展性差。于是我们决定用SpringBootVue搭建一个轻量级但五脏俱全的在线创作社区。这个系统最核心的特点是采用前后端分离架构…

2026/10/15 6:55:51 阅读更多 →
正念与心流:10分钟呼吸练习,让专注成为生命底色

正念与心流:10分钟呼吸练习,让专注成为生命底色

1. 先说清楚:我们到底在谈什么你有没有过这样的时刻:明明手头有一件重要的事要做,却忍不住五分钟刷一次手机;开会时脑子飘到晚上吃什么;想读几页书,眼睛盯着一行字,心里却已经把明天的待办事项过…

2026/10/15 6:55:51 阅读更多 →
Oracle 数据实时入仓 Doris 和 StarRocks 怎么做?CDC、全量迁移与 5 种方案对比

Oracle 数据实时入仓 Doris 和 StarRocks 怎么做?CDC、全量迁移与 5 种方案对比

在很多企业系统中,Oracle 负责在线事务处理,Doris 或 StarRocks 负责报表、数据分析和实时数据服务。当订单、用户、支付和日志数据持续增长时,直接在 Oracle 上运行复杂统计 SQL,可能影响线上业务。因此,很多团队会建…

2026/10/15 6:55:51 阅读更多 →
SpringBoot+Vue+MyBatis构建企业级电商平台实战

SpringBoot+Vue+MyBatis构建企业级电商平台实战

1. 项目概述"企业级网购平台管理系统"是一个基于SpringBootVueMyBatis技术栈的完整电商解决方案。这套源码包含了电商平台的核心功能模块,采用前后端分离架构设计,数据库使用MySQL,适合快速构建中小型B2C或B2B电商平台。我在实际电…

2026/10/15 6:55:51 阅读更多 →
聚簇索引vs非聚簇索引:从底层原理到实战避坑全解析

聚簇索引vs非聚簇索引:从底层原理到实战避坑全解析

做后端开发这几年,索引相关的坑我踩过不少。面试被问过无数次“聚簇索引和非聚簇索引区别”,带新人的时候也发现,大部分同学对这两个词的理解停留在“一个有序一个无序”或者“聚簇索引就是主键”这种模糊层面。一旦落到实际业务,…

2026/10/15 6:55:51 阅读更多 →
盲盒商城软件开发案例:连接概率说明、微信支付、在线开赏与积分兑换

盲盒商城软件开发案例:连接概率说明、微信支付、在线开赏与积分兑换

盲盒商城的购买过程与普通商品商城有所不同。用户在付款前,需要了解盲盒价格、可抽取内容和相关规则;完成支付后,再进入开赏环节。商品展示、概率说明、支付结果和积分记录之间,需要形成清晰的操作顺序。 某公司的这套盲盒商城软件…

2026/10/15 6:54:51 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →