嗨(`・ω・´),我们又见面啦,上一篇我们讲了文件操作入门(上)—— 文件类型及顺序读写基础(含打开关闭),这一篇我们来继续讲解文件操作的其他内容——随机读写、缓冲区等等,让我们来继续了解吧!

文件的随机读写十分简单好理解,具体如下:
作用:fseek函数是根据文件指针的位置和偏移量来定位文件指针(文件内容的光标)。
int fseek ( FILE * stream, long int offset, int origin );参数:
stream还是文件指针,指向FILE对象的指针

offest表示偏移量,可正可负
origin有三种

我们现在来验证,我们建一个文本输入abcdefg,进行操作


#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "r"); //test.txt中存的是abcdefg
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件--开始时光标在文件开始(即a)
int ch = fgetc(pf); //读完之后光标向后移动一位指向b
printf("%c", ch); //a
ch = fgetc(pf); //读完之后光标向后移动一位指向c
printf("%c", ch); //b
fseek(pf, 4, SEEK_CUR); //从b开始向后数4个字节,数到f
ch = fgetc(pf);
printf("%c", ch); //g
fclose(pf);
pf = NULL;
return 0;
}结果符合

作用:返回值文件指针相对于起始位置的偏移量
long int ftell(FILE* stream);这里就不解释了,进行测试代码如下
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "r"); //test.txt中存的是abcdefg
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件--开始时光标在文件开始(即a)
int ch = fgetc(pf); //读完之后光标向后移动一位指向b
printf("%c", ch); //a
ch = fgetc(pf); //读完之后光标向后移动一位指向c
printf("%c", ch); //b
printf("%d",ftell(pf));
fclose(pf);
pf = NULL;
return 0;
}我们只读了俩个字符,所以偏移量为2,结果如下:

正确
作用:让文件指针的位置回到文件的起始位置。
void rewind ( FILE * stream );直接看代码
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt", "r"); //test.txt中存的是abcdefg
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件--开始时光标在文件开始(即a)
int ch = fgetc(pf); //读完之后光标向后移动一位指向b
printf("%c", ch); //a
ch = fgetc(pf); //读完之后光标向后移动一位指向c
printf("%c", ch); //b
rewind(pf);//指针回到开头
ch = fgetc(pf); //读完之后光标向后移动一位指向b
printf("%c", ch); //a
fclose(pf);
pf = NULL;
return 0;
}我们读取ab后返回开头,现在再读取还读取a,结果如下:

函数名 | 函数原型 | 核心作用 | 关键参数/说明 |
|---|---|---|---|
fseek | int fseek(FILE *stream, long offset, int origin); | 移动文件指针到指定位置,支持随机访问 |
|
ftell | long ftell(FILE *stream); | 获取当前文件指针相对于文件开头的字节偏移量 |
|
rewind | void rewind(FILE *stream); | 快速将文件指针重置到文件开头 |
|
读写文件时需准确判断是否到达末尾,否则会读取无效数据或写入失败,核心依赖 feof 和 ferror 函数(需配合读写函数使用)。
注意在文件读取过程中,不能⽤用feof函数的返回值直接来判断文件的是否结束。
feof**int feof(FILE *stream);while (!feof(fp)) { fread(...); }(可能多读取一次无效数据)while (fread(...) == 预期个数) { ... },读写失败后再用 feof 判断是否因文件尾导致。ferror**int ferror(FILE *stream);#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
int ch = 0;
while ((ch = fgetc(pf)) != EOF)
{
printf("%c\n", ch);
}
//判断是什么原因导致读取结束的
if (feof(pf))
{
printf("文件遇到末尾,读取正常结束\n");
}
else if (ferror(pf))
{
perror("fgetc");
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}ANSC标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。

文件缓冲区的核心作用是减少磁盘 IO 次数、提升文件读写效率,同时优化数据传输的稳定性。磁盘 IO(读写磁盘)速度远低于内存操作(约差 1000 倍以上),缓冲区作为 “中间暂存区”,避免 CPU 频繁等待磁盘响应。
代码测试:
#include <stdio.h>
#include <windows.h>
//VS2022 WIN11环境测试
int main()
{
FILE* pf = fopen("test.txt", "w");
fputs("abcdef", pf); //先将代码放在输出缓冲区
printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
Sleep(10000);
printf("刷新缓冲区\n");
fflush(pf); //刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
//注:fflush 在高版本的VS上不能使用了
printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
Sleep(10000);
fclose(pf);
//注:fclose在关闭文件的时候,也会刷新缓冲区
pf = NULL;
return 0;
}其中Sleep表示等待多少毫秒再下一步;fflush(pf)是手动刷新缓冲区,即将存放在缓冲区里的数据传出,再刷新前文件不会显示我们写入的内容,关闭文件也算手动刷新
我们结合我们所学,将一个文件中的内容输入到另一个文件中
#define _CRT_SECURE_NO_WARNINGS // 屏蔽Visual Studio对"非安全函数"的警告(如fopen)
#include <stdio.h> // 包含文件操作函数(fopen、fgetc等)和输入输出函数
#include <stdlib.h> // 包含标准库函数(如程序退出相关)
int main()
{
// 以只读模式打开源文件test.txt,准备读取内容
FILE* pin = fopen("test.txt", "r");
// 检查文件是否打开成功:若pin为NULL,说明打开失败(如文件不存在)
if (pin == NULL)
{
perror("fopen"); // 打印错误原因(格式:"fopen: 具体错误信息")
return 1; // 非0值退出,标识程序异常结束
}
// 以只写模式打开目标文件test2.txt,准备写入内容(若文件不存在则创建,存在则清空原内容)
FILE* pout = fopen("test2.txt", "w");
// 检查目标文件是否打开成功
if (pout == NULL)
{
fclose(pin); // 若打开失败,先关闭已成功打开的源文件,避免资源泄露
pin = NULL; // 将指针置空,防止野指针
return 1; // 异常退出
}
int ch = 0; // 用于存储fgetc读取的字符(用int类型接收,以处理EOF)
// 循环读取源文件内容:每次读取一个字符,直到读到文件尾(EOF)
while ((ch = fgetc(pin)) != EOF)
{
fputc(ch, pout); // 将读取到的字符写入目标文件
}
// 操作完成后,关闭两个文件,释放系统资源
fclose(pin);
fclose(pout);
// 将指针置空,避免后续误操作导致的野指针问题
pin = NULL;
pout = NULL;
return 0; // 程序正常结束
}嗨,o( ̄ε ̄*) 文章到这里就结束啦,本篇与上一篇讲了文件操作的重要知识点,相信大家都有所收获,下一篇我们将要讲解编译与链接,敬请期待,欢迎大家在评论区补充和建议!我们下篇再见٩(๑❛ᴗ❛๑)۶!