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)和理解缓冲区机制,是编写可靠文件处理程序的基础。

相关推荐
齊家治國平天下2 小时前
Android 14 Vehicle HAL (VHAL) 设计与实现深度解析
android·aaos·carservice·车载开发·android 14·vhal·vehicle hal
天空'之城2 小时前
C 语言工业级通用组件手写 04:阻塞队列
c语言·嵌入式开发·阻塞队列·多线程开发
Java搬码工3 小时前
CompletableFuture 完整详解 + 全场景使用案例
java
许心月3 小时前
Java学习资料网站汇总
java
c238563 小时前
第二篇:《测试指挥官:可视化单题自测框架(含 assert 实操)》
java·数据库·c++·算法·安全性测试
帅次4 小时前
Kotlin 与 Java 互操作:混合工程里的平台类型与 API 边界
java·开发语言·kotlin·suspend·nullable
X-⃢_⃢-X4 小时前
一、第一阶段:认识 Spring Boot
java·spring boot·后端
前端工作日常4 小时前
我学习到的Java程序的生命周期
java·后端
SunnyDays10114 小时前
Java 实现 PDF 页面删除、排序、旋转和裁剪
java·pdf
人工干智能5 小时前
科普:Pandas 索引器 loc 与 iloc 的编程思维
java·人工智能·pandas