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

相关推荐
大鹏说大话7 分钟前
C++ 内存布局详解:类、虚函数、虚表底层原理
java·开发语言
还是鼠鼠37 分钟前
Spring AI连接DeepSeek与通义千问:application.yaml配置详解
java·通义千问·spring ai·deepseek
YuforiaCode1 小时前
第十六届蓝桥杯 2025 C/C++组 数列差分
c语言·c++·蓝桥杯
计算机小白一个1 小时前
蓝桥杯 Java B 组之哈希表应用(两数之和、重复元素判断)
java·数据结构·算法·蓝桥杯
alexhilton2 小时前
Android XR 开发入门完全指南
android·kotlin·android jetpack
sunburn-3 小时前
Java 队列全面详解:从入门到面试实战
java·开发语言·汇编·ide·idea
vx-程序开发3 小时前
springboot农产品运输服务平台---附源码75498
java·javascript·spring boot·python·eclipse·django·php
捷瑞电子工坊4 小时前
C语言二维数组在内存中是如何存储的?
c语言·二维数组·内存存储·数组底层
zzh___zzh4 小时前
SQL 窗口函数 ROW_NUMBER、RANK、DENSE_RANK 常用方法笔记
java
计科土狗4 小时前
GESP六级专题之类与对象
java·前端·数据库