🚀write in front🚀
📜所属专栏: c语言学习
🛰️博客主页:睿睿的博客主页
🛰️代码仓库:🎉VS2022_C语言仓库
🎡您的点赞、关注、收藏、评论,是对我最大的激励和支持!!!
关注我,关注我,关注我,你们将会看到更多的优质内容!!
文章目录
- 前言
- 一、文件的随机读写
- 1、fseek函数:
- 2、ftell函数:
- 3、rewind函数:
- 4、综合使用:
- 二、文本文件与二进制文件:
- 三、文件结束的判定:
- 1.错误使用 feof 函数:
- 2.一些判断文件结束的总结:
- 2.1. 文本文件读取是否结束:
- 2.2. 二进制文件的读取结束判断,
- 3.判断原因的两个函数:
- 四、缓冲区的简单介绍
- 总结:
前言
在上一篇文章中上一篇文章文件操作知识大全(上),我们学习了文件操作的相关知识,比如顺序读写,文件的打开与关闭,文件指针等等。今天我们再来补充一些常用的知识点!
一、文件的随机读写
1、fseek函数:
根据文件指针的位置和偏移量来定位文件指针
函数格式:
int fseek(FILE* stream, long int offset, int origin);
注意事项:
- 其中“ offset ”为相对于指针位置的指针偏移量。
- 其中“ origin ”为指针位置,其参数有三种:
“ SEEK_CUR ”表示文件指针当前位置;
“ SEEK_END ”表示文件末尾的位置;
“ SEEK_SET ”表示文件开始位置。
int main()
{
FILE* pf = fopen("test.txt", "w");
fputs("abcd", pf);
fclose(pf);
pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
}
else
{
int ch = fgetc(pf);
printf("%c\n", ch);//a
ch = fgetc(pf);
printf("%c\n", ch);//b
ch = fgetc(pf);
printf("%c\n", ch);//c
//如果继续往下读,必然是d
//但是我们调整一下,去读取:b
//fseek(pf, -2, SEEK_CUR);
fseek(pf, 1, SEEK_SET);
ch = fgetc(pf);
printf("%c\n", ch);//b
}
return 0;
}
运行结果:
2、ftell函数:
返回文件指针相对于起始位置的偏移量
函数格式:
long int ftell(FILE* stream);
3、rewind函数:
让文件指针的位置回到文件的起始位置(其实相当于fseek(stream,0,SIZE_SET))
函数格式:
void rewind(FILE* strname);
4、综合使用:
int main()
{
FILE* pf = fopen("test.txt", "w");
fputs("abcd", pf);
fclose(pf);
pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen");
}
else
{
int ch = fgetc(pf);
printf("%c\n", ch);//a
ch = fgetc(pf);
printf("%c\n", ch);//b
ch = fgetc(pf);
printf("%c\n", ch);//c
//如果继续往下读,必然是d
//但是我们调整一下,去读取:b
//fseek(pf, -2, SEEK_CUR);
fseek(pf, 1, SEEK_SET);
ch = fgetc(pf);
printf("偏移一个字符后是%c\n", ch);//b
printf("总共便宜了%d\n个位置", ftell(pf));
rewind(pf);
ch = fgetc(pf);
printf("回到起始位置后是%c\n", ch);//a
}
return 0;
}
运行结果:
二、文本文件与二进制文件:
- 数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。
- 如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。
所以,一个数据在内存中是怎么存储的呢?
字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节。
我们举个栗子:
int main()
{
int a = 10000;
FILE* p = fopen("test.txt", "wb");
//“wb”表示以只写模式打开二进制文件
if (p == NULL)
{
perror("FileOpen");
return 0;
}
fwrite(&a, 4, 1, p);
//将变量a中的数据,每四个字节存储一次,写入文件指针p所指向的文件
fclose(p);
p = NULL;
return 0;
}
通过文本文件发现看不懂:
其实原因大家都知道,我们是以2进制的形式传进去的,文本文件就以这个2进制打印了字符。所以我们现在来用二进制形式看看该文件(16进制)!
每四个字节进行划分:
0000 0000 0000 0000 0010 0111 0001 0000
于是得到:
00 00 27 10
又因为我们的vs是小端存储,于是在进行压栈时会将数据进行倒置存储,于是就有了该结果。
三、文件结束的判定:
1.错误使用 feof 函数:
在一段时间的交流中,我发现有很多小伙伴们都错误的使用了 feof 函数,将其用于判断文件是否读取结束 ,而这种使用方式是错误的。
我们应该记住:
- 在文件的读取过程中,不能通过 feof 函数的返回值来判定文件是否读取结束。
- 该函数的作用为:在已经确定文件读取结束的情况下,用于判定文件读取结束的原因
2.一些判断文件结束的总结:
2.1. 文本文件读取是否结束:
要判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
例如:
fgetc 判断是否为 EOF .
fgets 判断返回值是否为 NULL .
int main()
{
int c;
//注意:int,非char,要求处理EOF
FILE* fp = fopen("test.txt", "r");
if (!fp)
{
perror("File opening failed");
return 1;
}
// fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
while ((c = fgetc(fp)) != EOF)
// 标准C I/O读取文件循环
{
putchar(c);
}
//判断是什么原因结束的
if (ferror(fp))
{
puts("I/O error when reading");
}
else if (feof(fp))
{
puts("End of file reached successfully");
}
fclose(fp);
fp = NULL;
return 0;
}
2.2. 二进制文件的读取结束判断,
判断返回值是否小于实际要读的个数。
例如:
fread判断返回值是否小于实际要读的个数。
#include<stdio.h>
enum {
SIZE = 5
};
int main(void)
{
double a[SIZE] = { 1.,2.,3.,4.,5. };
FILE* fp = fopen("test.bin", "wb");
//必须用二进制模式
fwrite(a, sizeof * a, SIZE, fp);
//写 double 的数组
fclose(fp);
double b[SIZE];
fp = fopen("test.bin", "rb");
size_t ret_code = fread(b, sizeof * b, SIZE, fp);
//读 double 的数组
//判断是否读取成功
if (ret_code == SIZE)
{
puts("Array read successfully, contents: ");
for (int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
putchar('\n');
}
//寻找读取失败的原因:
else {
// error handling
if (feof(fp))
{
printf("Error reading test.bin: unexpected end of file\n");
}
else if (ferror(fp))
{
perror("Error reading test.bin");
}
}
fclose(fp);
fp = NULL;
return 0;
}
3.判断原因的两个函数:
四、缓冲区的简单介绍
文件缓冲区是用以暂时存放读写期间的文件数据而在内存区预留的一定空间。
ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”.从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。
要使缓冲区的内容进入内存或者计算机硬盘有两种方法,第一种是缓冲区充满自动填入,第二个是主动刷新缓冲区。
举个例子:
#include <stdio.h>
#include <Windows.h>
//VS2022 WIN10环境测试
int main()
{
FILE* pf = fopen("test.txt", "w");
fputs("abcdef", pf);
//先将代码放在输出缓冲区
printf("睡眠10秒\n");
//已经写数据了,但是打开test.txt文件,发现文件没有内容
Sleep(10000);
printf("刷新缓冲区\n");
fflush(pf);
//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
//注:fflush 在高版本的VS上不能使用了
printf("再睡眠10秒\n");
//此时,再次打开test.txt文件,文件有内容了
Sleep(10000);
fclose(pf);
//注:fclose在关闭文件的时候,也会刷新缓冲区
pf = NULL;
return 0;
}
所以在这里,各位小伙伴们一定要注意了,因为缓冲区的存在,数据只有在填满缓冲区后才会进行真正的写入或读取,所以在 C 语言程序代码的编写过程中,我们一定要在文件操作结束时关闭文件,否则就可能导致文件的读写操作出现问题。
总结:
经过今天内容的补充,我们关于文件操作与管理的知识就全部学完了,不知道小伙伴们是否掌握了呢?
更新不易,辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~ 你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!
专栏订阅:
每日一题
c语言学习
算法
智力题
更新不易,辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~ 你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!