一、基本流程
1. 定义文件指针的基本语法
FILE *fp;
2. 打开文件:fopen()
打开文件时需要指定文件路径和打开模式:
FILE *fp = fopen("example.txt", "w");
⚠️调用 fopen 后必须检查返回值是否为 NULL
(例如文件不存在或权限不足会导致打开失败)
3. 关闭文件:fclose()
完成操作后,务必关闭文件以释放资源并确保缓存区的数据写入磁盘
fclose(fp);
二、常用文件打开模式
| 模式 | 含义 | 说明 |
|---|---|---|
r | 只读 | 文件必须存在;若不存在,返回 NULL |
w | 只写 | 覆盖写入;文件若存在则清空,不存在则创建 |
a | 追加 | 从文件末尾接着写;文件不存在则创建 |
r+ | 读写 | 文件必须存在,可读可写 |
w+ | 读写 | 清空并创建可读可写的文件 |
a+ | 读写/追加 | 追加写,可读;文件不存在则创建 |
如果是二进制文件(如图片、视频),在模式后加
b即可,e.g.rb,wb.
三、读写文件的3种常见方式
1. 文本按行读写(最常见:fputs / fgets)
写入一行:
#include <stdio.h>
int main() {
FILE *fp = fopen("test.txt", "w");
if (fp == NULL) {
printf("无法打开文件!\n");
return 1;
}
fputs("Hello World!\n", fp);
fputs("GrizzlyBlog\n", fp);
fclose(fp);
return 0;
}
读取一行:
#include <stdio.h>
int main() {
FILE *fp = fopen("test.txt", "r");
if (fp == NULL) {
printf("无法打开文件!\n");
return 1;
}
char buffer[100];
// 循环读取每一行,直到 EOF (文件末尾)
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
printf("%s", buffer);
}
fclose(fp);
return 0;
}
2. 格式化读写(类似于 printf / scanf)
使用 fprintf 和 fscanf 可以非常方便地保存和读取结构化数据.
①格式化写入:fprintf()
FILE *fp = fopen("data.txt", "w");
int age = 20;
char name[] = "Grizzly";
fprintf(fp, "Name: %s, Age: %d\n", name, age);
fclose(fp);
②格式化读取:fscanf()
FILE *fp = fopen("data.txt", "r");
char name[20];
int age;
// 从文件中提取数据并存入变量
fscanf(fp, "Name: %s, Age: %d", name, &age);
printf("解析结果: 姓名=%s, 年龄=%d\n", name, age);
fclose(fp);
3. 二进制数据读写(fwrite / fread)
如果你需要保存数组、结构体等二进制数据,可以使用 fwrite 和 fread
#include <stdio.h>
typedef struct {
int id;
char name[20];
float score;
} Student;
int main() {
Student s1 = {101, "Bob", 95.5f};
// 1. 以二进制写入模式打开
FILE *fp = fopen("student.dat", "wb");
fwrite(&s1, sizeof(Student), 1, fp); // 写入 1 个结构体
fclose(fp);
// 2. 以二进制读取模式打开
Student s2;
fp = fopen("student.dat", "rb");
fread(&s2, sizeof(Student), 1, fp); // 读取 1 个结构体
fclose(fp);
printf("读取结构体: ID=%d, 姓名=%s, 成绩=%.1f\n", s2.id, s2.name, s2.score);
return 0;
}
四、文件指针定位(随机访问)
跳到文件的特定位置进行读写常用函数:
1.fseek():移动文件指针到指定位置
语法定义:
int fseek(FILE *stream, long offset, int origin);
stream:文件指针offset:偏移量(要移动多少个字节).正数表示往后移,负数表示往前移.origin:基准位置(从哪里开始算偏移量)包括: ①SEEK_SET:从文件开头算 ②SEEK_CUR:从当前位置算 ③ **SEEK_END**:从文件末尾算
// 1. 跳到文件开头往后第 10 个字节的位置
fseek(fp, 10, SEEK_SET);
// 2. 从当前位置再往后跳 5 个字节
fseek(fp, 5, SEEK_CUR);
// 3. 跳到文件末尾(常用于准备追加,或结合 ftell 计算文件大小)
fseek(fp, 0, SEEK_END);
// 4. 跳到文件倒数第 10 个字节的位置
fseek(fp, -10, SEEK_END);
2. ftell():获取当前位置
语法定义:
long ftell(FILE *stream);
应用:获取文件大小先用 fseek 拖到最末尾,再用 ftell
看当前位置,结果就是文件的总字节数:
fseek(fp, 0, SEEK_END); // 1. 移到文件最末尾
long fileSize = ftell(fp); // 2. 获取当前位置,即文件总大小(字节)
printf("文件大小为: %ld 字节\n", fileSize);
3. rewind():重置文件指针
语法定义:
void rewind(FILE *stream);
等同于执行:
fseek(fp, 0, SEEK_SET);
**使用场景:**当程序先读了一遍文件来统计行数,统计完后,想再读一遍文件把内容存进数组里。如果不把指针重置回开头,第二次读取就会直接读到文件末尾(EOF),什么也读不到。这时候调用一下
rewind(fp); 就能重新从头读起.
4. 实例:计算文件大小
FILE *fp = fopen("test.txt", "r");
if (fp != NULL) {
fseek(fp, 0, SEEK_END); // 指针移到结尾
long size = ftell(fp); // 获取当前偏移量(即文件字节数)
printf("文件大小: %ld 字节\n", size);
fclose(fp);
}