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

【C语言程序设计】第34篇:文件的概念与文件指针

1 引言

到目前为止,我们所有的程序数据都存储在内存中,程序结束后就消失了。但在实际应用中,我们需要将数据长期保存,比如:

  • 保存用户配置,下次启动时读取

  • 记录程序运行日志

  • 处理外部数据文件

  • 生成报告文档

这就需要用到文件操作。C语言通过文件指针和一系列库函数提供了对文件的访问能力。

c

#include <stdio.h> int main(void) { FILE *fp; /* 文件指针 */ /* 打开文件 */ fp = fopen("test.txt", "w"); if (fp == NULL) { printf("文件打开失败\n"); return 1; } /* 写入数据 */ fprintf(fp, "Hello, File!\n"); /* 关闭文件 */ fclose(fp); return 0; }

本章我们将深入理解文件操作背后的概念和机制。


2 文件的基本概念

2.1 什么是文件

文件(File)是存储在外部介质(如磁盘)上的数据的集合,是程序进行输入输出的基本单位。操作系统以文件为单位管理数据。

从程序的角度看,文件就是字节序列——一系列可以读取或写入的字节。

2.2 文件的分类

根据数据的组织形式,文件分为两大类:

文件类型特点示例
文本文件以字符为单位,每字节存储一个字符的ASCII码.txt,.c,.html
二进制文件以字节为单位,按内存中的存储形式原样存放.exe,.jpg,.mp3

2.3 文本文件

文本文件存储的是字符序列,每个字节对应一个字符的ASCII码。

c

/* 在文本文件中存储整数 12345 */ fprintf(fp, "%d", 12345); /* 实际写入:'1' '2' '3' '4' '5' 共5字节 */

特点

  • 内容可以直接用文本编辑器查看

  • 每行通常以换行符结束(不同系统换行符不同)

  • 读写时需要格式转换(如数字与字符串的转换)

  • 占用空间通常比二进制大

2.4 二进制文件

二进制文件按照数据在内存中的二进制形式原样存储。

c

/* 在二进制文件中存储整数 12345 */ int n = 12345; fwrite(&n, sizeof(int), 1, fp); /* 实际写入:int 的二进制表示,通常4字节 */

特点

  • 不能用文本编辑器直接查看(可能显示乱码)

  • 读写速度快,无需格式转换

  • 存储紧凑,占用空间小

  • 跨平台可能存在字节序问题

2.5 文本文件 vs 二进制文件

比较维度文本文件二进制文件
存储形式字符的ASCII码数据的二进制形式
可读性可直接阅读不可直接阅读
空间效率较低(如数字12345占5字节)较高(int 12345占4字节)
读写效率需格式转换,较慢直接读写,较快
换行符处理系统自动转换(\n ↔ \r\n)不处理,原样写入
适用场景配置文件、源代码、文档可执行文件、图像、音频

3 流的概念

3.1 什么是流

(Stream)是C语言中对输入输出设备的抽象。它提供了一种统一的方式,无论数据来自键盘、屏幕、文件还是网络,程序都可以用相同的方式读写。

text

程序 ←→ 流 ←→ 设备(文件、键盘、屏幕等)

3.2 流的分类

C语言中的流分为两类:

流类型说明示例
文本流以行为单位,处理换行符转换文本文件
二进制流字节原样传输,不转换二进制文件

3.3 标准流

当C程序启动时,系统会自动打开三个标准流:

流名称文件指针默认设备用途
标准输入stdin键盘读取输入
标准输出stdout屏幕输出正常信息
标准错误stderr屏幕输出错误信息

c

#include <stdio.h> int main(void) { int n; fprintf(stdout, "请输入一个整数:"); /* 正常输出 */ fscanf(stdin, "%d", &n); /* 标准输入 */ if (n < 0) { fprintf(stderr, "错误:输入不能为负数\n"); /* 错误输出 */ return 1; } return 0; }

4 FILE 结构体与文件指针

4.1 FILE 结构体

FILE是C语言标准库定义的一个结构体类型,用于保存文件的相关信息。它通常包含:

  • 文件位置指示器(当前读写位置)

  • 缓冲区指针和缓冲区大小

  • 文件状态标志(是否到达末尾、是否有错误等)

  • 文件描述符(操作系统层面的文件标识)

c

/* 在 stdio.h 中的典型定义(简化示意) */ typedef struct { int level; /* 缓冲区填充程度 */ unsigned flags; /* 文件状态标志 */ char fd; /* 文件描述符 */ unsigned char hold; /* 无缓冲区时读取的字符 */ int bsize; /* 缓冲区大小 */ unsigned char *buffer; /* 数据缓冲区 */ unsigned char *curp; /* 当前活动指针 */ unsigned istemp; /* 临时文件标志 */ short token; /* 用于有效性检查 */ } FILE;

注意:在实际编程中,我们不需要关心FILE结构体的内部细节,只需要通过FILE*指针使用标准库函数即可。

4.2 文件指针

文件指针(File Pointer)是指向FILE结构体的指针,用于标识一个流,是所有文件操作函数的核心参数。

c

FILE *fp; /* 定义文件指针 */

文件指针的作用:

  • 标识打开的文件

  • 保存文件的状态信息

  • 传递给文件操作函数(如fprintffscanffreadfwrite

4.3 文件指针与普通指针的区别

方面文件指针普通指针
指向内容FILE结构体任意类型的数据
操作方式通过库函数(fread/fwrite等)通过解引用(*)
使用者库函数内部维护程序员直接操作

5 文件操作的基本流程

5.1 三步曲

文件操作通常遵循三个步骤:

  1. 打开文件fopen()返回文件指针

  2. 读写文件fprintf()fscanf()fread()fwrite()

  3. 关闭文件fclose()释放资源

c

#include <stdio.h> int main(void) { FILE *fp; /* 1. 打开文件 */ fp = fopen("example.txt", "r"); if (fp == NULL) { perror("文件打开失败"); return 1; } /* 2. 读写文件(这里只是示例) */ char buffer[100]; while (fgets(buffer, sizeof(buffer), fp) != NULL) { printf("%s", buffer); } /* 3. 关闭文件 */ fclose(fp); return 0; }

5.2 为什么需要关闭文件

关闭文件(fclose)非常重要,原因如下:

  1. 刷新缓冲区:确保所有数据真正写入磁盘

  2. 释放资源:释放FILE结构体和系统文件句柄

  3. 防止数据丢失:程序异常结束时,缓冲区数据可能丢失

c

/* 错误:忘记关闭文件 */ FILE *fp = fopen("data.txt", "w"); fprintf(fp, "重要数据"); /* 程序结束,但数据可能还在缓冲区,未写入磁盘! */

6 文件打开模式

fopen的第二个参数指定打开模式,常用的有:

6.1 文本文件模式

模式含义文件存在时文件不存在时
"r"只读正常打开返回 NULL
"w"只写内容被清空创建新文件
"a"追加从末尾写入创建新文件
"r+"读写正常打开返回 NULL
"w+"读写内容被清空创建新文件
"a+"读和追加从末尾写入创建新文件

6.2 二进制文件模式

在文本模式后加b表示二进制模式:

模式含义
"rb"二进制只读
"wb"二进制只写
"ab"二进制追加
"rb+"二进制读写
"wb+"二进制读写(清空)
"ab+"二进制读和追加

6.3 模式选择示例

c

FILE *fp; fp = fopen("data.txt", "r"); /* 读取文本文件 */ fp = fopen("data.txt", "w"); /* 写入文本文件(覆盖) */ fp = fopen("log.txt", "a"); /* 追加到文本文件末尾 */ fp = fopen("image.jpg", "rb"); /* 读取二进制文件 */ fp = fopen("data.bin", "wb"); /* 写入二进制文件 */

7 常见错误与注意事项

7.1 忘记检查文件是否成功打开

c

FILE *fp = fopen("nonexistent.txt", "r"); fprintf(fp, "test"); /* 如果 fp 为 NULL,程序崩溃! */ /* 正确做法 */ FILE *fp = fopen("nonexistent.txt", "r"); if (fp == NULL) { perror("打开文件失败"); return 1; }

7.2 忘记关闭文件

c

void process_file(void) { FILE *fp = fopen("data.txt", "r"); /* 处理文件... */ /* 忘记 fclose(fp) */ } /* 文件句柄泄漏!程序运行期间无法再次打开该文件 */

7.3 混淆文本模式和二进制模式

在 Windows 系统上,文本模式下换行符\n会被自动转换为\r\n,二进制模式下则不会。

c

/* 在 Windows 上 */ FILE *fp = fopen("test.txt", "w"); fprintf(fp, "Hello\nWorld"); /* 实际写入:Hello\r\nWorld */ fp = fopen("test.bin", "wb"); fprintf(fp, "Hello\nWorld"); /* 实际写入:Hello\nWorld */

7.4 对同一文件进行多次打开

同一个文件可以被多次打开,每次得到不同的文件指针,各自维护独立的位置指示器。

c

FILE *fp1 = fopen("data.txt", "r"); FILE *fp2 = fopen("data.txt", "r"); fgetc(fp1); /* 读取第一个字符,fp1 位置前移 */ fgetc(fp2); /* 也读取第一个字符,fp2 位置独立 */

7.5 使用已关闭的文件指针

c

FILE *fp = fopen("data.txt", "r"); fclose(fp); fprintf(fp, "test"); /* 错误!fp 已无效 */

7.6 忽略错误处理

文件操作可能因各种原因失败(磁盘满、权限不足等),应该检查返回值:

c

if (fprintf(fp, "data") < 0) { perror("写入失败"); }

8 本章小结

本章系统介绍了文件的基本概念和文件指针:

1. 文件的类型

  • 文本文件:存储字符的ASCII码,可直接阅读

  • 二进制文件:存储数据的二进制形式,紧凑高效

2. 流的概念

  • 程序与设备之间的抽象,提供统一接口

  • 标准流:stdinstdoutstderr

  • 文本流和二进制流的区别

3. FILE 结构体与文件指针

  • FILE结构体保存文件的状态信息

  • 文件指针是FILE*类型,标识一个流

  • 程序员只需使用指针,不关心内部细节

4. 文件操作三步曲

  1. fopen()打开文件(检查返回值)

  2. 读写操作

  3. fclose()关闭文件(必须!)

5. 打开模式

  • "r":只读

  • "w":写入(清空)

  • "a":追加

  • "r+""w+""a+":读写模式

  • b表示二进制模式

6. 常见错误

  • 忘记检查fopen返回值

  • 忘记关闭文件

  • 混淆文本和二进制模式

  • 使用已关闭的文件指针


参考资料

[1] C语言标准(ISO/IEC 9899:2018)- 第7.21节:文件访问

[2] Kernighan, B. W., & Ritchie, D. M. (1988). The C Programming Language (2nd ed.). Prentice Hall.

[3] Prinz, P., & Crawford, T. (2005). C in a Nutshell. O'Reilly Media.

[4] 腾讯云开发者社区. C语言文件操作详解

[5] CSDN博客. 文本文件与二进制文件的区别

[6] 阿里云开发者社区. FILE结构体深度剖析

http://www.jsqmd.com/news/503694/

相关文章:

  • Python实战:用statsmodels库搞定ARIMA时间序列预测(附完整代码)
  • C#实战:用WebView2和HandyControl打造透明股票盯盘工具(附源码)
  • 实时跟踪算法比较研究:PDA与JPDA在多目标杂波环境下的应用与分析
  • EcomGPT-中英文-7B电商模型Typora风格文档生成:优雅的本地商品知识管理
  • 从矩阵SVD到张量T-SVD:算法演进与核心思想剖析
  • 如何通过llama.cpp模型注册表快速部署30+主流大语言模型:新手入门终极指南
  • 实战演练:基于快马AI开发电商订单与库存联动的数据库应用
  • 为什么BERT和GPT都选择Transformer?拆解NLP模型进化史中的关键设计
  • 2026年压力测试工具对比与性能测试平台选型指南
  • 利用smart_rtmpd与ffmpeg实现高效RTMP推流全攻略
  • [具身智能-51]:视觉生成模型是模型学习海量的视频,掌握视觉像素Token的统计规律,大语言模型是模型学习互联网海量的文本,掌握语言文字Token的统计规律。
  • 互联网+医院分级诊疗大数据云平台解决方案:分级诊疗系统、互联网医院平台、移动医生站与护士站、患者端应用、运营管理端、大数据中心
  • MATLAB调用GEBCO高精度水深数据构建Delft3D模型地形(.dep)全流程解析
  • springboot员工宿舍管理系统(编号:10039121)
  • 2007-2024年上市公司污染物排放数据
  • 节省80%操作时间:OnmyojiAutoScript自动化工具全方位解决方案
  • 别再瞎调参了!用sklearn的KFold做五折交叉验证,这3个参数(shuffle/random_state/n_splits)你真的搞懂了吗?
  • 保姆级教程:用Sonic+ComfyUI制作数字人视频,新手也能轻松搞定
  • 任务分解:用多个小模型实现更经济的AI
  • Hi3519芯片开发过程笔记:九、Uboot修改网口芯片phy硬件参数
  • Qwen3-ASR-1.7B运维指南:基于Linux的系统监控与性能调优
  • 【123页PPT】集团信息化顶层规划方案:信息化战略、IT应用架构规划、IT基础设施规划、IT治理规划、信息系统实施计划
  • EDK II架构解密:现代UEFI固件开发的模块化革命
  • AI大模型训练大规模智算中心建设方案
  • 交稿前一晚!9个AI论文工具全场景通用测评,助你高效完成毕业论文与科研写作
  • Python爬虫进阶:用Selenium+PyWin32实现付费文档自动化下载(附完整代码)
  • WuliArt Qwen-Image Turbo应用案例:IP形象设计→多角度线稿→上色全流程
  • STM32F103与AX58100的EtherCAT从站开发:FSMC接口配置避坑指南
  • 蓝图构建:大模型应用开发全景图
  • AgentCPM的AIGC能力展示:自动生成行业研究简报与新闻快讯