重点
"r"
/"w"
/"a"
等)的选择与使用
fgetc/fputc
、fgets/fputs
、fread/fwrite
)
fseek
、ftell
、rewind
)
难点
feof()
的误用(常见错误点)
讲解
互动提问
.c
(源代码)、.obj
(目标文件)、.exe
(可执行文件)
.txt
(文本)、.bin
(二进制)、.log
(日志文件)
C:\code\test.txt
../data/data.txt
)
示例
// 打开当前目录下的data.txt文件
FILE *fp = fopen("data.txt", "r");
对比
特性 | 文本文件 | 二进制文件 |
---|---|---|
存储方式 | ASCII字符序列 | 原始二进制数据 |
空间效率 | 较低(如整数10000占5字节) | 更高效(如整数占4字节) |
处理速度 | 较慢(需字符处理) | 更快(直接读写内存) |
典型用途 | 文本数据(日志、配置) | 图像、音频、结构化数据 |
代码示例
// 写入文本文件
FILE *text_fp = fopen("text.txt", "w");
fprintf(text_fp, "10000"); // 写入5个字符
// 写入二进制文件
FILE *bin_fp = fopen("data.bin", "wb");
int num = 10000;
fwrite(&num, sizeof(int), 1, bin_fp); // 写入4字节
fopen()
FILE *fopen(const char *filename, const char *mode);
模式参数:
"r"
:只读; "w"
:只写(覆盖); "a"
:追加
"rb"
/"wb"
:二进制模式
NULL
。fclose()
int fclose(FILE *stream);
0
表示成功。
代码示例
FILE *fp = fopen("data.txt", "w");
if (fp == NULL) {
perror("Failed to open file");
exit(EXIT_FAILURE);
}
fclose(fp);
函数 | 功能 | 参数示例 |
---|---|---|
fgetc() | 读取单个字符 | char ch = fgetc(fp); |
fputc() | 写入单个字符 | fputc('A', fp); |
fgets() | 读取一行文本 | fgets(buffer, 100, fp); |
fputs() | 写入字符串 | fputs("Hello", fp); |
函数 | 功能 | 参数示例 |
---|---|---|
fread() | 读取二进制数据 | fread(buffer, size, count, fp); |
fwrite() | 写入二进制数据 | fwrite(data, sizeof(int), 1, fp); |
练习
fseek()
:定位文件指针int fseek(FILE *stream, long offset, int whence);
SEEK_SET
:从文件开头开始
SEEK_CUR
:从当前位置开始
ftell()
:获取当前位置偏移量long ftell(FILE *stream);
rewind()
:重置文件指针到文件开头void rewind(FILE *stream);
示例:修改文件中间数据
// 在二进制文件的第10个字节处写入字符'X'
FILE *fp = fopen("data.bin", "rb+"); // 需要读写权限
if (fp == NULL) {
perror("Failed to open file");
exit(EXIT_FAILURE);
}
// 移动到第10个字节的位置
fseek(fp, 10, SEEK_SET);
fputc('X', fp); // 写入单个字符
fclose(fp);
互动提问
"如何快速获取文件的总大小?"
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
rewind(fp);
常见误区:不要依赖feof()
错误示例:
while (!feof(fp)) {
c = fgetc(fp);
// 处理字符
}
问题:当读取到文件末尾时,feof()
会返回true
,但此时已经读取了无效的EOF
,导致循环多执行一次。
正确方法
文本文件:
fgetc()
返回EOF
时结束:
while ((c = fgetc(fp)) != EOF) {
// 处理字符
}
fgets()
返回NULL
时结束:
while (fgets(buffer, 100, fp) != NULL) {
// 处理行
}
二进制文件:
fread()
返回值小于预期读取的字节数时结束:
size_t elements_read = fread(buffer, sizeof(int), 10, fp);
while (elements_read == 10) {
// 处理数据
elements_read = fread(buffer, sizeof(int), 10, fp);
}
练习
编写一个程序,统计文本文件中的单词数量。
缓冲机制的作用
写操作:数据先写入内存缓冲区,减少磁盘IO次数,提高效率。
读操作:数据从磁盘一次性读入缓冲区,减少频繁访问磁盘的开销。
关键函数
fflush()
:强制刷新缓冲区
int fflush(FILE *stream);
关闭文件时自动刷新缓冲区:
fclose(fp); // 自动调用fflush(fp)
示例:缓冲区的影响
FILE *fp = fopen("log.txt", "a");
fprintf(fp, "Start processing...\n"); // 数据暂存在缓冲区
// 程序突然崩溃,此时数据可能未写入文件!
fflush(fp); // 显式刷新,确保数据落地
互动讨论
"为什么在多线程程序中需要谨慎使用fflush()
?"
(提示:缓冲区竞争可能导致数据不一致)
打开文件(fopen)→ 读写操作 → 关闭文件(fclose)
fopen()
返回的文件指针是否为NULL
feof()
,改用读取函数的返回值
fflush()
确保数据持久化
基础练习
input.txt
内容复制到output.txt
。
附录:常见错误与调试技巧
"r"
模式打开不存在的文件会失败。
fgets()
的第二个参数要足够大。