C语言文件:文件操作完全指南

C语言文件:文件操作完全指南

文件操作使程序能够持久保存数据,是实现信息长期存储的关键。本文将系统讲解文件的分类、打开与关闭、顺序读写、随机读写、文件结束判定以及缓冲区机制,帮助读者掌握C语言文件处理的核心方法。

目录


一、为什么使用文件

程序运行时的数据存储在内存中,程序退出后内存释放,数据即丢失。要实现数据持久化保存,必须将数据写入磁盘文件。文件操作使得数据在程序多次运行间保持可用。


二、什么是文件

文件分为两大类:

  • 程序文件 :包含 .c 源文件、.obj 目标文件、.exe 可执行文件。
  • 数据文件:程序运行时读写的数据文件,如存储配置、日志、用户数据等。

本讲主要讨论数据文件

文件名

文件名由三部分组成:文件路径 + 文件名主干 + 文件后缀,例如 c:\code\test.txt


三、二进制文件和文本文件

根据数据存储形式分类:

  • 二进制文件 :数据以内存中的二进制形式直接存储。例如整数 10000 占4字节。
  • 文本文件 :数据以ASCII码形式存储。例如整数 10000 转为字符 '1' '0' '0' '0' '0',占5字节。
c 复制代码
// 以二进制写入整数
int a = 10000;
FILE* pf = fopen("test.bin", "wb");
fwrite(&a, 4, 1, pf);
fclose(pf);

四、文件的打开和关闭

4.1 流和标准流

  • :抽象概念,表示数据输入输出的通道,程序员通过流操作各种设备。
  • 标准流 :C程序启动时默认打开三个流:
    • stdin(标准输入流,通常对应键盘)
    • stdout(标准输出流,通常对应屏幕)
    • stderr(标准错误流,通常对应屏幕)

4.2 文件指针

每个打开的文件在内存中有一个 FILE 结构体变量,存放文件信息。我们通过 FILE* 指针操作文件。

c 复制代码
FILE* pf;   // 文件指针变量

4.3 文件打开与关闭

  • fopen:打开文件,返回 FILE* 指针。
  • fclose:关闭文件,释放资源。
c 复制代码
FILE* pf = fopen("myfile.txt", "w");  // 以只写方式打开文本文件
if (pf != NULL) {
    fputs("hello", pf);
    fclose(pf);
}

常用打开模式

模式 含义
"r" 只读,文件必须存在
"w" 只写,文件不存在则创建
"a" 追加,文件不存在则创建
"rb" 二进制只读
"wb" 二进制只写
"r+" 读写,文件必须存在
"w+" 读写,不存在则创建

注意 :文件操作完成后必须调用 fclose 关闭文件。


五、文件的顺序读写

函数 功能 适用流类型
fgetc 读一个字符 所有输入流
fputc 写一个字符 所有输出流
fgets 读一行字符串 所有输入流
fputs 写一行字符串 所有输出流
fscanf 格式化读取 所有输入流
fprintf 格式化写入 所有输出流
fread 二进制读取 文件输入流
fwrite 二进制写入 文件输出流

对比 scanf/printffscanf/fprintf

  • scanf 默认从 stdin 读取,printf 默认输出到 stdout
  • fscanf 可从任意输入流读取,fprintf 可向任意输出流写入。
c 复制代码
// 示例:从文件读取整数并打印
FILE* pf = fopen("data.txt", "r");
int n;
fscanf(pf, "%d", &n);
printf("%d\n", n);
fclose(pf);

六、文件的随机读写

6.1 fseek:移动文件指针

c 复制代码
int fseek(FILE* stream, long offset, int origin);
  • origin 取值:
    • SEEK_SET:文件开头
    • SEEK_CUR:当前位置
    • SEEK_END:文件末尾
c 复制代码
fseek(pf, 9, SEEK_SET);   // 从开头偏移9字节
fputs("sam", pf);         // 覆盖写入

6.2 ftell:获取当前偏移量

c 复制代码
long pos = ftell(pf);   // 返回从文件开头到当前指针的字节数

6.3 rewind:重置文件指针到开头

c 复制代码
rewind(pf);   // 等价于 fseek(pf, 0, SEEK_SET);

七、文件读取结束的判定

重要 :不能直接用 feof 判断文件是否结束,而是应在读取操作后,用 feof 判断结束原因是否为遇到文件尾。

文本文件读取循环

c 复制代码
int c;
while ((c = fgetc(fp)) != EOF) {   // 判断是否结束
    putchar(c);
}
if (feof(fp))
    printf("正常到达文件末尾\n");
else if (ferror(fp))
    printf("读取错误\n");

二进制文件读取循环

c 复制代码
double b[5];
size_t ret = fread(b, sizeof(double), 5, fp);
if (ret == 5) {
    // 成功读取
} else {
    if (feof(fp)) printf("文件提前结束\n");
    else if (ferror(fp)) printf("读取错误\n");
}

八、文件缓冲区

ANSIC 采用缓冲文件系统,系统为每个文件在内存中开辟一个缓冲区。

  • 输出时:数据先写入缓冲区,缓冲区满后才真正写入磁盘。
  • 输入时:从磁盘读取数据到缓冲区,再从缓冲区逐个送入程序。

刷新缓冲区 :使用 fflush(fp) 强制将缓冲区内容写入磁盘;fclose 也会自动刷新缓冲区。

c 复制代码
FILE* pf = fopen("test.txt", "w");
fputs("abcdef", pf);   // 数据仍在缓冲区
fflush(pf);            // 刷新到磁盘
fclose(pf);            // 自动刷新

结论:操作文件后应正确关闭或刷新缓冲区,避免数据丢失。


总结:文件操作实现了数据的持久化存储。通过 fopen/fclose 管理文件生命周期,使用顺序读写函数(fgetc/fputc/fgets/fputs/fscanf/fprintf/fread/fwrite)或随机读写函数(fseek/ftell/rewind)进行数据访问。正确判断文件结束(结合 feofferror)和理解缓冲区机制,是编写可靠文件处理程序的基础。

相关推荐
零陵上将军_xdr1 小时前
API 签名防重放机制:基于 HMAC-SHA256 的设计与实现
java·学习·安全架构
ch.ju1 小时前
Java程序设计(第3版)第四章——set-get方法
java·开发语言
lpd_lt1 小时前
如何让AI生成项目的单元测试,propmt技巧详解
java·人工智能·单元测试·ai编程
_日拱一卒1 小时前
LeetCode:17电话号码的字母组合
java·数据结构·算法·leetcode·职场和发展
2501_916007471 小时前
不用 Mac 也可以 Windows下管理iOS描述文件的非Xcode完整指南
android·ios·小程序·https·uni-app·iphone·webview
我是一颗柠檬1 小时前
【Java项目技术亮点】Outbox事件驱动模式:解决分布式事务的终极方案
java·开发语言·分布式·后端·中间件·kafka
_Evan_Yao1 小时前
为 LLM 预留“插座”:设计可插拔的 AI 能力底座
java·人工智能·后端·python
我登哥MVP1 小时前
Spring Boot 从“会用”到“精通”:Converter 原理
java·spring boot·servlet·maven·mybatis·converter
Clf丶忆笙1 小时前
搭建支持多语言开发的Quarkus环境:Java、Kotlin与Scala全栈指南
java·开发语言·云原生·kotlin·scala·quarkus