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/printf 与 fscanf/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)进行数据访问。正确判断文件结束(结合 feof 与 ferror)和理解缓冲区机制,是编写可靠文件处理程序的基础。

相关推荐
Navigator_Z10 分钟前
LeetCode //C - 1286. Iterator for Combination
c语言·算法·leetcode
BLUcoding17 分钟前
接口服务公网超时排查记录:SecureRandom 阻塞问题分析与解决
java·linux·springboot·aes·securerandom
yuniko-n32 分钟前
【JUC】Lock 和 synchronzied 锁
java
西柚小萌新39 分钟前
【LLM&&AI应用开发 八股文】--4.3.Agent智能体(下)
java·开发语言·数据库
北极有牛42 分钟前
cpp学习笔记--常量指针
java·开发语言·算法
java资料站1 小时前
二、Spring AI Alibaba · ChatModel
java·windows·spring
用户69371750013841 小时前
2026,程序员的时代拐点到了
android·前端·后端
十年Java程序媛1 小时前
Java 接口和抽象类对比|Java8 新特性,抛弃老旧八股,正确选型
java·spring boot·后端
caoerzhong1 小时前
JeeWMS 开源 WMS 部署避坑指南:Java 仓库管理系统的环境基线、四类根因与可复现交付
java·开发语言·开源
用户3721574261351 小时前
Java 合并 PDF 文件:完整合并、指定页面合并与流合并
java