
简介这份面向C语言初学者的文件读写入门文档围绕文件打开、写入、读取与关闭的完整流程展开重点解决初学者对FILE指针、fopen模式、fprintf与fgets等标准库函数理解不深、示例代码难以看懂的问题。压缩包内仅含1个doc文件约14KB体量轻便适合课堂跟练、课后复习或实验前预习。文档用可直接运行的代码片段串联知识点覆盖写模式创建文件、读模式逐行读取、字符缓冲区处理、打开失败判断及资源释放等环节并配有注释便于读者边看边改、对照运行结果理解每一步作用减少照抄示例却不知其所以然的困扰。目前已有104人学习适合刚接触C语言文件操作、希望借助短小示例建立整体认知的学习者也能为后续学习二进制文件读写、文件定位等内容打下基础并逐步形成规范的编码习惯。1. 先别急着抄代码C语言文件读写到底是个什么东西第一次听到「C语言 文件读写」这六个字很多人的反应是我循环还没搞明白怎么突然冒出来一个文件其实你早就跟文件打过无数次交道了——你敲的.c源代码是文件编译出来的可执行程序是文件桌面上那个 txt 也是文件。所谓文件读写就是让程序自己去打开一个文件、往里写字或者从里面把字读出来而不是靠你手动复制粘贴。这件事的价值特别朴素程序一关变量里的数据就全没了写进文件数据才留得下来。所以凡是需要「记住上次结果」的小工具——记账、统计、保存设置——都绕不开它。这份资料用两段十几行的示例代码把这扇门推开很适合零基础的人先跑通、再理解不用一开始就啃厚书。2. 为什么新手也该早点学会文件读写让程序开始有记性2.1 内存是草稿纸硬盘才是笔记本先建立一个最基础的画面感。你写的每一个变量比如int score 90;都住在内存里。内存这东西速度快得离谱但它有个特点断电就清空程序一退出就归零。你可以把内存想成一张草稿纸随手算、随手写算完揉一揉扔掉不心疼。硬盘也就是文件住的地方更像一本笔记本。写得慢一点翻开找也慢一点但合上本子明天再打开字还在。C 语言的文件读写本质就是给你的程序配一支笔需要长期保留的东西从草稿纸抄到笔记本上下次开工再从笔记本里翻出来接着算。这个区别看着简单却决定了很多程序能不能成立。一个只能把成绩算出来打印在屏幕上的程序关掉窗口就什么都没了而一个能把成绩存进scores.txt的程序下次打开还能接着往下加人。新手最容易忽略的正是这一步写出来的程序「只能看一次」用起来就没有任何黏性。2.2 入门只需要记住四个动作开、判、读写、关文件操作看着函数挺多其实流程特别固定一共四步背下来就行。第一步打开文件拿到一个「门把手」第二步判断这个门把手有没有拿到手没拿到就直接收工第三步才是真正的写或者读第四步把门关上把东西落实。那个「门把手」在 C 语言里叫文件指针写法是FILE *fp;。FILE是标准库提供的一个类型你不用关心它里面装了什么就把它当成一张登记表这个文件叫什么、现在读到第几个字节、是读还是写全在这张表里记着。你手里握着fp就等于握着这张表后面所有动作都通过它来完成。入门阶段真正需要记住的函数没几个下面这张表可以先扫一眼不用背跑通例子之后再回头看会顺很多。函数干什么用新手最该注意的点fopen打开文件返回文件指针一定要判断返回值是不是NULLfprintf按格式往文件里写内容用法几乎等于printf只是多一个fpfgets从文件里读一行要给它一块缓冲区和一个长度fclose关闭文件写完不关内容可能没真正落盘另外要知道一件事文件分「文本文件」和「二进制文件」两类。新手先只碰文本文件就是能用记事本打开、能看懂的那种。二进制文件比如自己存的图片、结构体数组读写要换成fread/fwrite那是后面的事现在完全不用管。2.3 上手之前的最低准备会编译、会建文件夹就够了有人会担心前置知识不够。说句实在话跑通这两个例子你只需要三样东西会写一个带main的 C 文件、会用gcc把它编译成可执行程序、会在命令行里cd到自己建的那个文件夹。指针、数组、结构体这些在这个阶段只要不害怕就行用不到多深。唯一建议提前养成的习惯是专门建一个空文件夹放练习代码。因为文件读写会在「当前工作目录」里生成文件如果你在乱七八糟的目录里跑程序生成的文件找都找不到新手很容易在这里翻车。我第一次练的时候程序明明打印了「写入完成」翻遍桌面也找不到example.txt最后发现它躺在编译时所在的那个目录里——血泪经验提前建个干净文件夹能省掉这一出。还有一点心理准备文件读写这部分的报错特别「安静」。它不像语法错误那样编译不过很多时候程序正常跑完、正常打印但文件就是空的或者内容不对。所以后面每一步都要有验证动作别光看屏幕上那行「完成」。3. 第一个例子怎么跑把两行字写进文件3.1 先把骨架记住打开—判断—写入—关闭写文件这段代码骨架永远是同一个模子你把它抄下来当模板用完全没问题。模子长这样先声明FILE *fp;然后fp fopen(文件名, 模式);紧接着一句if (fp NULL) { ... }挡住失败的情况然后才是若干行写操作最后fclose(fp);。这里唯一需要动脑的是「模式」。模式就是个字符串告诉系统你打算怎么对待这个文件。新手最先接触的是三个w是只写而且会先把文件清空r是只读文件必须已经存在a是追加在文件末尾接着写不会清空原有内容。提示w模式的清空动作是没有后悔药的。文件名一旦写错、又刚好撞上你某个重要文件内容当场就没了。练习阶段务必用新建的练习文件别拿真实资料上的文件名试手。3.2 第一段完整代码把两行字写进 example.txt新建一个文件叫write_demo.c把下面这段抄进去。抄的时候别用复制粘贴式的「跳过」每一行注释都读一遍读完再编译。#include stdio.h int main() { // 声明文件指针后面所有文件操作都靠它 FILE *fp; // 以写入模式打开 example.txt文件不存在会自动创建 fp fopen(example.txt, w); // 打开失败时 fopen 返回空指针必须拦住否则后面必崩 if (fp NULL) { printf(无法打开文件\n); return 1; } // 往文件里写第一行用法和 printf 一样只是多了个 fp fprintf(fp, Hello, World!\n); // 写第二行\n 是换行漏掉的话内容会全挤在一行 fprintf(fp, 这是一个文件写入示例。\n); // 关闭文件把缓冲区里的内容真正刷到磁盘 fclose(fp); printf(写入完成。\n); return 0; }逐块说一下在干嘛。第一行#include stdio.h是把标准输入输出库引进来FILE、fopen、fprintf、fclose全在这个库里不写这行编译器一个都不认识。fp fopen(example.txt, w);这一句是真正的动作。example.txt是文件名也可以写成data/example.txt这种带路径的形式w是模式。执行完这句系统会在当前工作目录里创建或清空这个文件并给你一个文件指针。中间那个if (fp NULL)是新手最容易偷懒省掉、也最容易出事故的地方。打开失败的原因很多路径不存在、没有写权限、磁盘满了。C 语言不会自动帮你抛异常它只是悄悄给你一个空指针你不检查下一句fprintf就会直接让程序崩掉。fprintf(fp, ...)和printf(...)唯一的区别就是第一个参数多了一个往哪儿写的目标。你可以把它理解成「把这句话说到fp对应的文件里去」。格式化的能力完全一样%d、%s、%.2f照样能用所以后面想把整数、浮点数写进文件直接换成fprintf(fp, %d\n, score);就行。3.3 编译、运行、验证三步确认文件真写进去了代码抄完只是第一步一定要亲手跑一遍而且要有验证动作。编译和执行在命令行里做# 编译-o 后面是你想起的可执行文件名 gcc write_demo.c -o write_demo # 运行Windows 上文件名是 write_demo.exe直接敲 write_demo.exe ./write_demo跑完之后屏幕上应该出现写入完成。。但这行字只能证明程序跑完了不能证明文件写对了所以第三步必须验证把文件内容打印出来看一眼。# macOS / Linux 看文件内容 cat example.txt # Windows 命令行看文件内容 type example.txt预期输出是两行Hello, World!和这是一个文件写入示例。。如果什么都没输出说明文件是空的如果提示文件不存在说明你找错目录了——回去看看编译时你在哪个文件夹文件就在那儿。也可以直接双击用记事本打开看得更直观。如果编译这一步就报错八成是两件事函数名拼错比如把fprintf写成fprint或者忘了#include stdio.h。编译器的报错行号通常很准照着行号看就行不用慌。3.4 参数怎么改文件名、打开模式、写入内容跑通之后别急着往下走花五分钟改几个参数把这段代码变成你自己的比抄十遍管用。想换文件名就把example.txt换成note.txt、记录.txt之类。中文文件名在大多数现代系统上没问题但如果你后面在别的机器上打开出现乱码先怀疑这个改回英文名再试能省掉一堆玄学排查。想验证w的清空效果把程序连跑两次你会发现文件里还是那两行不会变成四行——因为每次w都先把文件清空重写。想让它接着往后写就把模式改成a// 改成追加模式重复运行会把内容一行行往后加而不是清空 fp fopen(example.txt, a);改完重新编译、再跑两次、再cat一次你会看到四行、六行。这个对比做一遍模式的概念就不用背了。想写进去自己的内容就把fprintf那两行改掉。比如写一个成绩记录// 把变量按格式写进文件%s 和 %d 的用法和 printf 完全一致 int score 92; fprintf(fp, 语文 %d 分\n, score); fprintf(fp, 姓名%s\n, A同学);4. 把写进去的读出来fgets 逐行读的套路4.1 读文件也是四步走只是中间换成循环写文件是一句一句往外送读文件则是要一句一句往回收。流程还是那个流程fopen打开判断空指针然后——这里是唯一的区别——读操作要套在循环里因为事先你不知道文件里有几行。最后照旧fclose。之所以要循环是因为读文件的函数一次只干一件事。fgets一次读一行读到就返回这行的地址读到文件末尾没东西可读了就返回一个特殊值NULL。于是「一直读到NULL为止」这句话翻译成代码就是while (fgets(...) ! NULL) { ... }这是 C 语言里处理文件的经典写法看多了会觉得挺顺眼。还有一件事得先讲明白读出来的东西得有地方放。所以在打开文件之前要先准备一块内存当容器行话叫缓冲区char buffer[256]; // 一块能装 255 个字符加一个结束符的内存你可以把它想成一个托盘fgets每次从文件里夹起一行放进托盘你的printf再从托盘里把这一行端出来给人看。文件本身是没法直接打印到屏幕上的中间必须有这个托盘。4.2 第二段完整代码把刚写的读回来新建一个read_demo.c和刚才的write_demo.c放在同一个文件夹里。这次打开模式换成r。#include stdio.h int main() { // 声明文件指针 FILE *fp; // 准备一块缓冲区用来临时存放读出来的每一行 char buffer[256]; // 以只读模式打开刚才写好的文件注意文件必须已经存在 fp fopen(example.txt, r); // 同样要判断失败就直接结束别往下走 if (fp NULL) { printf(无法打开文件\n); return 1; } // 每次读一行进 buffer读到文件末尾会返回 NULL循环自动结束 while (fgets(buffer, sizeof(buffer), fp) ! NULL) { // 把这一行原样打印到屏幕 printf(%s, buffer); } // 关闭文件释放资源 fclose(fp); printf(读取完成。\n); return 0; }这里两组新面孔char buffer[256]和while (fgets(...))。char buffer[256]是在内存里划出 256 个字节的位置专门用来接住每一行的内容。sizeof(buffer)就是 256用它比直接写数字 256 更稳妥哪天你把数组改成[1024]这句不用跟着改少一个出错的机会。while (fgets(buffer, sizeof(buffer), fp) ! NULL)这一整行可以这么念「只要还能从fp里读进一行到buffer最多装sizeof(buffer)那么多就继续循环」。当文件读完fgets返回NULL条件不成立循环自然退出不需要你自己去数行数。进了循环体只做一件事printf(%s, buffer);。注意这里不要写成printf(%s\n, buffer)——因为fgets把行末的换行符也一起读进来了再补一个\n就会多出空行看着像读错了一样。4.3 fgets 的三个参数往哪放、放多少、从哪读fgets的原型是char *fgets(char *str, int n, FILE *stream);三个参数各管一件事记成「往哪放、放多少、从哪读」就不会弄混。第一个buffer是目标地址告诉函数读到的东西往哪儿塞。这里必须是数组名或者一块有效的内存不能是没初始化的野指针否则程序直接崩。第二个sizeof(buffer)是数量上限意思是「最多读这么多个字符别超」。fgets读到换行符或者读满n-1个字符就会停下来然后自动在末尾补一个\0作为字符串结束标记。所以n传 256实际能装 255 个字符加一个结束符。第三个fp是文件指针也就是从哪个文件里读。返回值这块也值得多说一句。成功时它返回buffer的地址其实就是个非空值失败或者读到末尾返回NULL。所以在while里判断! NULL就够了不用去比较具体的地址。顺便提一种新手常犯的误用有人会想「我直接printf(%s, fp)把文件打印出来不就行了」。不行fp是文件指针不是字符串这样写只会打印一段看不懂的内存地址甚至直接崩。文件和内存之间永远隔着fgets这道搬运工序。4.4 缓冲区开多大255 和 1024 的差别超长行会怎样缓冲区大小是新手最容易随手写、又最容易埋雷的参数。写 256 不是硬性规定但要知道它的边界在哪。如果你某一行内容超过 255 个字符fgets不会报错它会「这一行装不下我先装 255 个」剩下的一半留到下一次循环再读出来。表现出来就是你的长行被硬生生切成两行打印。这不算 bug但对不知道原理的人来说特别像 bug能卡很久。所以处理可能有长行的文件比如日志、导出的数据把缓冲区写大一点1024 或 4096 都行// 长行文件的场景缓冲区开大一点更省心 char buffer[1024];反过来也别无限放大比如char buffer[1000000]直接放在main里有些环境下栈空间不够程序会在fopen之前就悄无声息地挂掉。练习阶段 256 到 4096 之间随便挑一个都安全。再补一个实用的改进点。实际处理数据时你往往想把读到的每一行再拆一拆比如「语文 92 分」里把科目和分数分别取出来。这时候可以在循环里用sscanf(buffer, %s %d, subject, score);用法和scanf一样只是从缓冲区里读而不是从键盘上读非常顺手。5. 新手最容易踩的坑五个翻车现场排查5.1 现象程序打印「无法打开文件」原因基本只有一个fopen返回了NULL。但为什么会失败得往下分。最常见的是读文件时文件根本不在那儿——你可能还没跑写的那段程序或者跑过但文件在另一个目录里。其次是路径写错比如程序在D:\code下跑你写fopen(D:\data\example.txt, r)结果反斜杠被当成转义字符了。还有就是想往只读的目录里写东西系统不让。解决办法是按顺序排查先确认文件确实存在用cat或资源管理器看一眼再把文件名换成最短的、不带任何路径的名字确保程序和文件在同一目录如果是 Windows 路径双写反斜杠写成D:\\data\\example.txt。这三步走完九成的打不开都能解决。5.2 现象屏幕上一片空白程序说「读取完成」但什么都没读出来原因通常是模式用错了或者读的位置不对。比如你写的时候用w写了内容读的时候却误把打开模式也写成了w——这一打开先把文件清空了自然读到空。还有一种情况是文件里确实有内容但你的循环条件写反了写成while (fgets(...) NULL)一次都进不去。解决办法先确认读的模式是r而不是w这是最容易被复制粘贴带错的地方。然后检查循环条件必须是! NULL。最后单独跑一次cat example.txt确认文件里真有东西把「文件是空的」和「代码读错了」这两种可能性分开。5.3 现象写进去的中文读出来变成一串看不懂的符号原因是编码不一致。你的源代码文件本身可能是某种编码而记事本或者终端在按另一种编码解释同一堆字节中文这种多字节字符就会显示成乱码。这跟 C 语言本身没关系问题出在「用什么方式看待这串字节」上。解决办法先用纯英文内容跑通全流程确认逻辑没问题这是最省时间的一步。跑通之后再换中文如果出现乱码把源文件保存成统一编码一般用 UTF-8并用同一个编辑器去打开生成的文件对照着看。如果只是练习把测试数据都换成英文能避开这个坑。5.4 现象内容明明写了但文件是空的或者少了最后一段原因是少了fclose或者程序在fclose之前就return了。往文件里写东西时系统并不是每写一句就立刻落到磁盘上而是先攒在内存的缓冲区里攒够一批再一起写下去。fclose就是那个「强制清仓」的动作。你不调用它程序一结束内存一清缓冲区里的东西就跟着没了。解决办法很直接每个fopen都配一个fclose成对出现。尤其是中间有return分支的时候要注意——如果if (fp NULL) return 1;之后还有正常的写入路径那没问题但如果你在写入之后、fclose之前又加了个提前return那就漏了。养成「打开完先想好关在哪」的习惯这类问题基本绝迹。5.5 现象第二次运行程序文件里只剩最后一次的内容原因是用了w模式。w的语义不是「准备写入」而是「清空并准备写入」这个细节很多人一开始没意识到以为是覆盖某一行的意思。实际上它是整篇推倒重来。解决办法就是换模式。需要保留旧内容往后接着写用a追加模式确实想每次重写才用w。判断标准很简单问自己一句这次运行的结果要不要跟上次的叠在一起要就a不要就w。想清楚了再写模式字符串比事后找原因容易得多。6. 下一步学什么从「能读写」到「用得顺」的三条路线跑通这两段代码之后其实已经跨过最难的那道坎了——你知道了一个文件从打开到关闭的完整生命周期。接下来往下走有三条路线按你手头的需求挑一条就行不用全学。第一条是「把数据攒起来」学会在循环里反复读文件把每行数据拆出来累加、计数、求平均。比如读一个成绩文件算出总分和人数。这条路练的是「读 解析」用到的就是fgets配sscanf不需要新知识。第二条是「换更细的读写方式」fgetc一次读一个字符、fputc一次写一个字符适合做字符级别的处理再往后是fread/fwrite处理二进制文件比如把一个结构体数组整体存进磁盘再整体读回来。这条路才是真正处理图片、自定义数据格式的入口。第三条是「让位置可控制」fseek和ftell能让指针跳到文件的任意位置回头看、跳着读都行。这条适合需要修改文件中间某段内容的场景比如一个小型的记录管理程序。如果只想先做点小东西练手下面这几个练习的难度是从低到高排的挑着做就行练习用到的知识大概要写多少行把用户输入的一行字追加进note.txta模式 fprintf20 行以内统计文件里一共有几行、几个字符fgets循环 计数器25 行左右读成绩文件输出总分和平均分fgetssscanf 累加40 行左右简易记事本能追加、能查看全文上面几项的组合60 行左右有一个习惯是我自己踩过坑之后强制养成的每次打开文件之前先在心里把「模式、路径、关在哪」这三件事默念一遍。模式决定文件是清空还是追加路径决定你找不找得到它关在哪决定了内容会不会丢。这三件事想清楚了剩下的函数调用几乎不会出错。从那以后我每次写文件相关的代码都会先把这三行骨架敲出来再填内容返工次数直线下降。希望这些能帮到你别怕出错先跑通第一个Hello, World!再说。本文还有配套的精品资源点击获取