当前位置: 首页 > news >正文

文件读写全套易错笔记

一、语法类错误(错误代码+修正代码)

错误1:fopen不做空指针判断

错误代码

FILE*fp=fopen("test.txt","r");fputc('a',fp);// 打开失败fp=NULL,直接崩溃

问题:文件打开失败不会捕获,后续读写直接程序崩溃。
修正代码

FILE*fp=fopen("test.txt","r");if(fp==NULL){perror("文件打开失败");return1;}fputc('a',fp);

错误2:绝对路径、转义符、路径格式错误

错误代码

// 问题1:单斜杠\是转义字符,识别失败FILE*fp=fopen("C:\Users\test.txt","rb");// 问题2:绝对路径绑定本机,换电脑直接找不到文件FILE*fp=fopen("D:/user/123/b.txt","rb");

推荐写法

// 双反斜杠转义绝对路径FILE*fp=fopen("C:\\Users\\test.txt","rb");// 最优:文件放exe同目录,使用相对路径FILE*fp=fopen("test.txt","rb");

错误3:打开模式和读写操作不匹配

错误代码

FILE*fp=fopen("data.txt","r");fputs("123",fp);// r只读模式执行写入,运行失败

要点:r/rb仅可读;w/wb/a/ab仅可写,模式和操作必须对应。

二、中文乱码问题

  1. 文本文件乱码
    现象:写入中文,记事本打开乱码。
    原因:VS默认编码GBK,记事本默认UTF‑8解析,字节编码不匹配。
    解决:
  • 记事本另存为,编码选择ANSI;
  • 统一全部代码、文件编码为UTF‑8;
  • 测试优先使用ASCII英文数字。
  1. 二进制文件损坏乱码
    原因:文本模式会自动转换\n\r\n,破坏二进制字节。
    解决:图片、视频、压缩包读写必须加b,使用rb/wb/ab

三、三大写入函数返回值区分(核心易混点)

1. fputc(单个字符写入)

原型:int fputc(int ch, FILE* fp);
成功:返回字符ASCII十进制值,如'a'返回97。
失败:返回EOF(-1)。

intret=fputc('a',fp);printf("%d",ret);// 输出97

2. fputs(字符串写入)

原型:int fputs(const char* str, FILE* fp);
成功:固定返回0。
失败:返回EOF(-1)。
注意:返回值为状态码,禁止用%c打印。

intret=fputs("hello",fp);printf("%d",ret);// 成功输出0

3. fwrite(二进制块批量写入)

原型:size_t fwrite(const void* buf, size_t 块大小, size_t 块数量, FILE* fp);
返回值:实际成功写入的完整块个数,不是字节数
判断失败:返回值 < 传入块总数。
总字节 = 返回值 × 单个块大小。
返回值是无符号数,禁止用%c打印。

4. fread(二进制读取)

原型:size_t fread(void* buf, size_t 块大小, size_t 块数量, FILE* fp);
返回值:读到的完整块个数;读取完毕返回0;不能用EOF判断结束

返回值汇总表

函数成功返回值失败/结束判断可用%c打印?
fputc字符ASCII码(97)ret == EOF✅可以
fputs固定0ret == EOF❌不建议
fwrite成功写入的块数量返回值<预期块数❌禁止
fread读到的块数量返回值 == 0❌禁止

fread‑fwrite拷贝易错点(货车模型通俗解析)

变量类比

arr相当于货车车厢,1024是车厢最大容量;n记录本趟实际装载字节数。
fread(缓冲区, 单块大小, 最多读多少块, 源文件)
‑ arr:货车车厢
‑ 1:1块=1字节
‑ 1024:一趟最多拉1024字节
‑ file1:源文件

循环执行流程:

  1. fread读取数据存入缓冲区,实际读到字节数赋值给n;
  2. n != 0:有数据就拷贝,n=0代表文件读完,循环结束。

fwrite(arr,1,n,file2)
‑ n只写入本次读到的数据;若固定写1024,缓冲区残留垃圾数据,文件末尾乱码。

完整运行流程:

  1. 二进制模式打开源文件file1(rb)、目标文件file2(wb);
  2. 缓冲区单次读取1024字节:读满就写1024字节,末尾不足就只写n字节;
  3. fread返回0,文件读取完毕,退出循环;
  4. 关闭文件,拷贝完成。

易错点:

  1. fwrite第三个参数必须填n,不能写1024;
  2. 二进制文件必须使用rb/wb;
  3. 缓冲区大小可改为4096、8192,缓冲区越大拷贝速度越快;
  4. n规范类型为size_t(无符号类型),int可运行但不规范。

错误缓冲区写法:

// 错误,最后一次写入垃圾数据while(1){fread(arr,1,1024,file1);fwrite(arr,1,1024,file2);}

正确模板:

charbuf[1024];size_tn;while((n=fread(buf,1,1024,file1))!=0){fwrite(buf,1,n,file2);}

拓展坑点:数组类型匹配

intarr[20];// 错误fread(arr,1,20,fp);// 正确,块大小使用sizeof(int)fread(arr,sizeof(int),20,fp);

四、char数组底层原理易错点

代码:char arr[] = {97,98,99};

  1. 内存底层只存储数字97、98、99;
  2. char占1字节,fwrite第二个参数填1刚好匹配;
  3. 记事本按照ASCII码将字节翻译为abc;
  4. int数组每个元素4字节,块大小必须改为sizeof(int),否则数据错乱乱码;
  5. 二进制数组没有'\0'结束符,和字符串规则区分开。

五、完整无BUG代码

1. 二进制文件拷贝代码(图片、视频通用)

#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>intmain(){// 二进制模式打开源文件、目标文件FILE*file1=fopen("src.txt","rb");FILE*file2=fopen("dest.txt","wb");// 空指针容错判断if(file1==NULL||file2==NULL){perror("打开失败");return1;}chararr[1024];// 货车缓冲区,最大1024字节size_tn;// 保存本次实际读取字节数while((n=fread(arr,1,1024,file1))!=0){fwrite(arr,1,n,file2);}fclose(file1);fclose(file2);system("pause");return0;}

2. 文本读写示例(fputc/fputs)

#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>intmain(){FILE*fp=fopen("test.txt","w");if(fp==NULL){perror("打开失败");return1;}fputc('A',fp);fputs("Hello World",fp);fclose(fp);system("pause");return0;}

六、通用注意事项(全部踩坑汇总)

  1. 文件打开模式区分
    w/wb:清空原有文件内容,从头写入;
    r/rb:只读,文件不存在直接打开失败;
    a/ab:末尾追加写入,不覆盖旧内容;
    ‑ 二进制文件读写必须带b(rb/wb/ab),防止换行符篡改文件。

  2. 必须执行fclose()
    ‑ 刷新缓冲区,把内存数据写入磁盘,避免数据丢失;
    ‑ 释放文件锁。

  3. EOF使用规则
    EOF(-1)仅用于fputc、fputs;fread读取结束判断返回值是否为0。

  4. 数据类型规范
    freadfwrite返回值类型是size_t(无符号整数),接收变量优先用size_t,禁止用int。

  5. VS编译警告配套处理
    ‑ system()未定义:添加头文件#include <stdlib.h>
    ‑ fopen警告:代码最顶部写#define _CRT_SECURE_NO_WARNINGS,放在所有头文件前面;

  6. 强制规则清单
    ① fopen之后立刻做空指针判断,避免空指针崩溃;
    ② Windows路径必须转义\\或使用/
    ③ 二进制文件模式必须带b;
    ④ 文件读写完毕一定要fclose;
    ⑤ 打开模式和读写操作保持匹配;
    ⑥ fread结束条件判断返回值是否为0,禁止使用EOF;
    ⑦ 宏定义写在头文件最前面。

http://www.cnnetsun.cn/news/3522818.html

相关文章:

  • Web Application Basics
  • SQL 数据库创建学生表+SQL 完整创建数据库代码(主文件+次文件+日志文件)
  • Ansible for Kubernetes多环境管理:从开发到生产的完整CI/CD流水线设计
  • 三类“核”底层差异拆解|全网独家复现传统滤波核、CNN可学习卷积核、SVM核函数、助力视觉预处理/特征提取/小样本分类精准涨点
  • HarmonyOS7 长按上下文菜单:用 bindContextMenu 做好快捷操作
  • Single主题社区贡献指南:如何参与开源项目开发
  • 自动设置 JAVA_HOME 和将 JDK 的 bin 目录添加到 PATH
  • Day5 哈希表part01
  • 3个关键功能让老旧Mac也能轻松制作Windows启动盘:WinDiskWriter深度解析
  • dynamic-struct版本演进:从v1.0到v1.4.0的重要变化指南
  • Jellium Desktop未来路线图:即将到来的5大令人兴奋的功能
  • 医疗机构 Hoxhunt 游戏化模拟钓鱼培训落地与人因风险治理研究
  • 有关线程池知识
  • 如何利用cpu_rec快速识别物联网设备固件中的CPU架构:10个实用技巧
  • 多维聚合实战:从GROUP BY到空间导航的数据分析跃迁
  • 90%开发者踩坑:MCP Resource注册≠模型能读取资源
  • 边缘推理引擎内建性能计数器设计:逐层延迟、内存峰值与功耗度量的采集和 Prometheus 导出方案
  • GimpPs终极指南:如何3步将GIMP界面秒变Photoshop专业风格
  • Windows Defender Remover终极指南:如何彻底移除系统自带杀毒软件
  • 3种方式解锁Windows终极权限:NSudo深度解析与实践指南
  • 硅基流动使用指南
  • 智谱清言GLM-4深度解析:6大核心能力对比实测(含推理速度、中文NLU得分、长文本吞吐量)
  • windows-terminal-quake安全与隐私:你需要知道的一切
  • 猫抓扩展:三分钟学会浏览器视频嗅探的终极免费方案
  • MPI-IS Mesh空间搜索:AABB树与最近点查询的实战应用
  • AI 模型输出异常的根因排查:幻觉、过时知识与推理断裂的区分诊断
  • 如何快速搭建ECS-Network-Racing-Sample:10分钟上手Unity DOTS多人游戏开发
  • ES6解构赋值的5个实用技巧:让JavaScript代码更简洁高效
  • 力扣-高频 SQL 50 题(基础版)-1484. 按日期分组销售产品
  • ## [特殊字符] 落地操作指南:从笨办法升级到聪明方法