C语言文件处理完全指南:fopen、fprintf、fread 与 fseek
C语言文件处理完全指南
本教程通过清晰实战示例,指导你掌握C语言文件I/O,涵盖文本与二进制操作。
文件是计算机存储上用于长期保存数据的逻辑容器。
为何使用文件?
- 数据在程序结束后持久化,防止信息丢失。
- 大数据集可一次存储,通过少量C命令快速访问。
- 文件可在计算机间移动无需修改。
文件类型
C语言主要涉及两类文件:
- 文本文件
- 二进制文件
文本文件
纯文本文件(如 .txt)可用任意文本编辑器编辑。易读、易维护、易传输,但占空间大、安全性低。
二进制文件
二进制文件(常用 .bin)以原始字节(0和1)存储数据。体积紧凑、不可人读、数据完整性和安全性更好。
核心文件操作
无论类型,C文件处理围绕四大操作:
- 创建新文件
- 打开现有文件
- 关闭文件
- 读取或写入文件
准备文件指针
所有文件操作需要 FILE * 指针引用打开的文件:
FILE *fptr;
打开文件:创建与编辑
fopen()(声明于 stdio.h)打开文件并返回 FILE * 指针。语法:
fptr = fopen("filename", "mode");
示例:
fopen("E:\\cprogram\\newprogram.txt", "w");
fopen("E:\\cprogram\\oldprogram.bin", "rb");
说明:
newprogram.txt以模式'w'创建(若不存在)并打开写入,覆盖现有内容。oldprogram.bin以模式'rb'打开仅供二进制读取;尝试写入将失败。
| 模式 | 含义 | 文件不存在时行为 |
|---|---|---|
r | 只读打开 | 返回 NULL |
rb | 二进制只读 | 返回 NULL |
w | 写入打开(覆盖) | 不存在则创建 |
wb | 二进制写入(覆盖) | 不存在则创建 |
a | 追加打开 | 不存在则创建 |
ab | 二进制追加 | 不存在则创建 |
r+ | 读写 | 返回 NULL |
rb+ | 二进制读写 | 返回 NULL |
w+ | 读写(覆盖) | 不存在则创建 |
wb+ | 二进制读写(覆盖) | 不存在则创建 |
a+ | 读取和追加 | 不存在则创建 |
ab+ | 二进制读取和追加 | 不存在则创建 |
关闭文件
完成所有I/O操作后,务必用 fclose() 关闭文件以释放资源并刷新缓冲区:
fclose(fptr);
文本文件I/O
文本文件用 fprintf() 和 fscanf() 处理,它们是 printf() 和 scanf() 的文件版,首参需 FILE * 指针。
示例 1:写入文本文件
#include <stdio.h>
#include <stdlib.h>
int main() {
int num;
FILE *fptr;
// 根据操作系统调整路径
fptr = fopen("C:\\program.txt", "w");
if (fptr == NULL) {
printf("打开文件失败\n");
exit(EXIT_FAILURE);
}
printf("输入一个数字: ");
scanf("%d", &num);
fprintf(fptr, "%d", num);
fclose(fptr);
return 0;
}
程序从用户获取整数并写入 program.txt。
示例 2:读取文本文件
#include <stdio.h>
#include <stdlib.h>
int main() {
int num;
FILE *fptr;
fptr = fopen("C:\\program.txt", "r");
if (fptr == NULL) {
printf("打开文件失败\n");
exit(EXIT_FAILURE);
}
fscanf(fptr, "%d", &num);
printf("读取值: %d\n", num);
fclose(fptr);
return 0;
}
在示例1后运行将显示存储的整数。
fgetc() 和 fputc() 等工具遵循相同模式。
二进制文件I/O
二进制文件用 fwrite() 写入、fread() 读取。两函数均接受四参数:数据指针、元素大小、元素个数、FILE * 指针。
写入二进制文件
fwrite(addressData, sizeData, numberData, filePointer);
示例 3:用 fwrite() 写入二进制文件
#include <stdio.h>
#include <stdlib.h>
struct threeNum {
int n1, n2, n3;
};
int main() {
int i;
struct threeNum num;
FILE *fptr;
fptr = fopen("C:\\program.bin", "wb");
if (fptr == NULL) {
printf("打开文件失败\n");
exit(EXIT_FAILURE);
}
for (i = 1; i < 5; ++i) {
num.n1 = i;
num.n2 = 5 * i;
num.n3 = 5 * i + 1;
fwrite(&num, sizeof(struct threeNum), 1, fptr);
}
fclose(fptr);
return 0;
}
读取二进制文件
fread() 签名与 fwrite() 对应:
fread(addressData, sizeData, numberData, filePointer);
示例 4:用 fread() 读取二进制文件
#include <stdio.h>
#include <stdlib.h>
struct threeNum {
int n1, n2, n3;
};
int main() {
int i;
struct threeNum num;
FILE *fptr;
fptr = fopen("C:\\program.bin", "rb");
if (fptr == NULL) {
printf("打开文件失败\n");
exit(EXIT_FAILURE);
}
for (i = 1; i < 5; ++i) {
fread(&num, sizeof(struct threeNum), 1, fptr);
printf("n1: %d\tn2: %d\tn3: %d\n", num.n1, num.n2, num.n3);
}
fclose(fptr);
return 0;
}
程序复现示例3写入的数据。
用 fseek() 实现随机访问
文件含大量记录时,顺序遍历到特定条目效率低。fseek() 移动文件指针到任意位置,实现直接访问。
语法
fseek(FILE *stream, long int offset, int whence);
stream:fopen()返回的指针。offset:移动字节数。whence:起始点 –SEEK_SET、SEEK_CUR或SEEK_END。
| 常量 | 含义 |
|---|---|
SEEK_SET | 从文件开头偏移。 |
SEEK_CUR | 从当前光标位置偏移。 |
SEEK_END | 从文件末尾偏移。 |
示例 5:用 fseek() 逆序读取
#include <stdio.h>
#include <stdlib.h>
struct threeNum {
int n1, n2, n3;
};
int main() {
int i;
struct threeNum num;
FILE *fptr;
fptr = fopen("C:\\program.bin", "rb");
if (fptr == NULL) {
printf("打开文件失败\n");
exit(EXIT_FAILURE);
}
// 移至最后一条记录
fseek(fptr, -sizeof(struct threeNum), SEEK_END);
for (i = 1; i < 5; ++i) {
fread(&num, sizeof(struct threeNum), 1, fptr);
printf("n1: %d\tn2: %d\tn3: %d\n", num.n1, num.n2, num.n3);
// 后退两条记录(当前+再一条)读取前一条
fseek(fptr, -2 * sizeof(struct threeNum), SEEK_CUR);
}
fclose(fptr);
return 0;
}
片段演示如何从最后一条记录开始逆序遍历二进制文件。
C语言
- 理解 STL 文件:3D 打印的基石
- 三角锉刀详解:设计特点、用途与保养
- C 语言文件 I/O 实战:创建、打开、读写与二进制操作
- C 语言头文件详解:类型、用法与最佳实践
- C 语言错误处理最佳实践:errno、perror 与 strerror 详解
- C++文件I/O完全指南:fstream读写、打开模式、定位指针与完整实例
- 掌握 C++ 信号处理:安全中断管理与优雅程序终止
- C# 异常处理完全指南:try-catch-finally、异常类型、自定义异常与最佳实践
- C# 文件 I/O 完全指南:流、读写操作与文件系统管理
- 掌握 Verilog 文件 I/O:打开、读取、写入和关闭
- Python 文件 I/O:掌握输入输出操作
- 掌握 Java 文件操作:java.io 包下的创建、读取、写入与删除