C语言文件操作指南:从打开关闭到读写实战
C程序运行时数据仅存于内存,退出后丢失。为实现数据持久化,需掌握C语言的文件操作机制。本文将解析文件类型与命名规则,演示如何通过fopen打开、fclose关闭文件,并利用fread、fwrite等函数完成数据的写入与读取。
数据持久化的必要性
在编写程序时,默认状态下所有数据存储在内存中。一旦程序运行结束或进程被终止,这些内存数据随即消失。这意味着下次启动程序时,必须重新录入所有信息,造成极大的不便。
为了解决这一痛点,我们需要引入文件的概念。通过将程序运行时产生的数据存储到磁盘中,可以实现跨会话的数据保留与调用。
文件基础概念
文件的分类
在程序设计中,文件主要分为两类:
- 程序文件:包括源程序文件(
.c)、目标文件(Windows环境下为.obj)以及可执行程序(.exe)。 - 数据文件:内容不一定是程序代码,而是程序运行时需要读入或输出的数据。本次讲解主要聚焦于此,利用它将运行时数据保存至磁盘。
文件名的构成
完整的文件名由三个部分组成:文件路径 + 文件名主干 + 文件后缀。
例如:c:\code\test.txt。
文件的打开与关闭
文件指针与FILE结构
在C语言中,系统对文件的操作统一采用“流”的方式,并通过一个名为 FILE 的结构体来记录文件状态。该结构体由标准库声明,通常包含缓冲区指针、文件大小、读写标志等信息。我们无需深究其内部细节,只需理解它是一个用于控制文件流的句柄。
核心API:打开与关闭
要进行文件读写,首先必须打开文件。ANSI C 标准规定使用 fopen 函数:
FILE * fopen ( const char * filename, const char * mode );
参数说明:
filename:文件名或路径。mode:打开模式,决定了允许进行的读写操作及文件不存在时的行为。
常用打开模式详解
| 模式 | 含义 | 文件不存在时 |
|---|---|---|
"r" (只读) | 打开已存在的文本文件进行输入 | 出错 |
"w" (只写) | 输出数据,若存在则清空,若不存在则创建 | 建立新文件 |
"a" (追加) | 向文件末尾添加数据 | 建立新文件 |
"rb" / "wb" / "ab" | 对应上述模式的二进制版本 | 同上 |
"r+" / "w+" / "a+" | 允许同时进行读写操作 | 根据主体模式决定 |
注:在I/O语境中,“输入”指数据流向内存(读取),“输出”指数据流向文件(写入)。
完成读写任务后,务必使用 fclose 关闭文件,以释放资源并刷新缓冲区:
int fclose ( FILE * stream );
打开与关闭示例
#include <stdio.h>
int main ()
{
FILE * pFile;
// 1. 打开文件
pFile = fopen ("myfile.txt","w");
// 2. 检查是否成功打开
if (pFile!=NULL)
{
fputs ("fopen example",pFile); // 写入数据
// 3. 关闭文件
fclose (pFile);
}
return 0;
}
文件的读写操作
当文件正确打开后,即可使用相应的IO函数进行数据交互。常用的函数如下表所示:
| 功能 | 函数名 | 适用场景 |
|---|---|---|
| 字符输入 | fgetc | 所有输入流 |
| 字符输出 | fputc | 所有输出流 |
| 文本行输入 | fgets | 所有输入流 |
| 文本行输出 | fputs | 所有输出流 |
| 格式化输入 | fscanf | 所有输入流 |
| 格式化输出 | fprintf | 所有输出流 |
| 二进制输入 | fread | 文件 |
| 二进制输出 | fwrite | 文件 |
实战案例:通讯录数据的保存与加载
以下是一个完整的工程应用示例,展示了如何定义数据结构,并使用二进制方式将通讯录数据保存到文件,以及如何从文件中恢复数据。这种方法效率高,且能精确还原复杂结构体。
// 假设已经定义了联系人结构体和通讯录结构
// struct contact_person { ... };
// typedef struct Contact { ... } Contact;
1. 保存数据 (Save)
目的:将内存中的通讯录数据整体写入磁盘文件。
void Save(Contact* con)
{
// 以二进制写模式打开
FILE* fp = fopen("contact.txt", "wb");
if (fp == NULL)
{
printf("Save()::%s", strerror(errno));
return;
}
else
{
// fwrite: 写入 count 个大小为 sizeof(struct contact_person) 的数据块
fwrite(con->data, sizeof(struct contact_person), con->count, fp);
}
fclose(fp); // 关闭并刷新
fp = NULL;
}
2. 加载数据 (Load)
目的:读取文件内容,按顺序填充至内存结构体中。
void Load(Contact* con)
{
// 以二进制读模式打开
FILE* fp = fopen("contact.txt", "rb"); // 注意读取二进制文件建议用 rb
if (fp == NULL)
{
printf("Load()::%s", strerror(errno));
return;
}
else
{
struct contact_person tmp;
// fread 返回成功读取的数据项个数
while (fread(&tmp, sizeof(struct contact_person), 1, fp))
{
Check_capacity(con); // 确保容量足够
con->data[con->count] = tmp; // 存入数组
con->count++; // 更新计数
}
}
fclose(fp);
fp = NULL;
}
上述代码清晰地展示了如何利用 fread 的返回值判断读取是否结束,是处理定长结构体序列的标准做法。
总结
C语言的文件操作核心在于管理 FILE* 指针的生命周期。遵循“先打开、后操作、最后关闭”的原则,根据业务需求选择正确的打开模式(如文本 vs 二进制)及读写函数,即可高效地解决数据持久化问题。
以上就是C语言文件操作方法与读写函数的详细内容,更多关于C语言文件操作技巧的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













