首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >文件操作入门(下)—— 随机读写、结尾判断、缓冲区及实战题目

文件操作入门(下)—— 随机读写、结尾判断、缓冲区及实战题目

作者头像
星轨初途
发布2026-01-09 14:37:56
发布2026-01-09 14:37:56
1060
举报
文章被收录于专栏:星轨初途星轨初途

前言

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

在这里插入图片描述
在这里插入图片描述

七、文件的随机读写

文件的随机读写十分简单好理解,具体如下:

1、fseek

作用:fseek函数是根据文件指针的位置和偏移量来定位文件指针(文件内容的光标)。

代码语言:javascript
复制
int fseek ( FILE * stream, long int offset, int origin );

参数:

stream还是文件指针,指向FILE对象的指针

在这里插入图片描述
在这里插入图片描述

offest表示偏移量,可正可负

origin有三种

在这里插入图片描述
在这里插入图片描述

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
#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;
}

结果符合

在这里插入图片描述
在这里插入图片描述

2、ftell

作用:返回值文件指针相对于起始位置的偏移量

代码语言:javascript
复制
long int ftell(FILE* stream);

这里就不解释了,进行测试代码如下

代码语言:javascript
复制
#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,结果如下:

在这里插入图片描述
在这里插入图片描述

正确

3、rewind

作用:让文件指针的位置回到文件的起始位置。

代码语言:javascript
复制
void rewind ( FILE * stream );

直接看代码

代码语言:javascript
复制
#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,结果如下:

在这里插入图片描述
在这里插入图片描述

4、总结

函数名

函数原型

核心作用

关键参数/说明

fseek

int fseek(FILE *stream, long offset, int origin);

移动文件指针到指定位置,支持随机访问

  1. origin:基准位置(SEEK_SET文件开头/SEEK_CUR当前位置/SEEK_END文件末尾);2. offset:偏移字节(正向后/负向前);3. 返回值:成功0,失败非0

ftell

long ftell(FILE *stream);

获取当前文件指针相对于文件开头的字节偏移量

  1. 返回值:有效偏移量(long类型),失败返回-1L;2. 常用场景:计算文件长度、记录指针位置

rewind

void rewind(FILE *stream);

快速将文件指针重置到文件开头

  1. 无返回值,等价于 fseek(stream, 0, SEEK_SET);2. 适用场景:重新读取文件、重置读写位置

八、文件读取结束的判定(避免读写越界)

读写文件时需准确判断是否到达末尾,否则会读取无效数据或写入失败,核心依赖 feofferror 函数(需配合读写函数使用)。

注意在文件读取过程中,不能⽤用feof函数的返回值直接来判断文件的是否结束。

1、判断文件读取是否结束方法

  • 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
  • ⼆进制⽂件的读取结束判断,判断返回值是否小于实际要读的个数。

2. 核心函数解析

  • 判断是否到文件尾:**feof**
  • 函数原型:int feof(FILE *stream);
  • 功能:当文件指针到达末尾时,返回非0值(真),否则返回0(假)。
  • 关键注意:必须在读写操作之后调用,不能直接用它判断是否“可以读写”。
    • 错误用法:while (!feof(fp)) { fread(...); }(可能多读取一次无效数据)
    • 正确用法:while (fread(...) == 预期个数) { ... },读写失败后再用 feof 判断是否因文件尾导致。
  • 判断读写错误:**ferror**
  • 函数原型:int ferror(FILE *stream);
  • 功能:若文件读写过程中发生错误(如权限不足、文件损坏),返回非0值,否则返回0。
  • 用途:区分“读写失败是因为文件尾”还是“因为错误”。

3. 正确判断结尾的示例(读取文本文件)

代码语言:javascript
复制
#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 频繁等待磁盘响应。

代码测试:

代码语言:javascript
复制
#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)是手动刷新缓冲区,即将存放在缓冲区里的数据传出,再刷新前文件不会显示我们写入的内容,关闭文件也算手动刷新

十、练习

我们结合我们所学,将一个文件中的内容输入到另一个文件中

代码语言:javascript
复制
#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( ̄ε ̄*) 文章到这里就结束啦,本篇与上一篇讲了文件操作的重要知识点,相信大家都有所收获,下一篇我们将要讲解编译与链接,敬请期待,欢迎大家在评论区补充和建议!我们下篇再见٩(๑❛ᴗ❛๑)۶!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-01-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 七、文件的随机读写
    • 1、fseek
    • 2、ftell
    • 3、rewind
    • 4、总结
  • 八、文件读取结束的判定(避免读写越界)
    • 1、判断文件读取是否结束方法
    • 2. 核心函数解析
    • 3. 正确判断结尾的示例(读取文本文件)
  • 九、文件缓冲区
  • 十、练习
  • 十一、结尾语
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档