目录
文本文件和二进制文件
概念
根据数据的组织形式,数据文件被称为文本文件或者二进制文件。
数据在内存中以二进制的形式存储,如果不加转换的输出到外存(磁盘),就是二进制文件。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件
一个数据在内存中是怎么存储的呢?
字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节。
通过VS2013可以查看二进制数值
直接看二进制文本看不出来,可以使用vs的功能添加现有项,这里我演示的是我一直用的test.txt,代码编译后是一个二进制的文件
这里VS2013测试能够显示,VS2019显示不出来。
能够看到4个字节,以小端存储的方式存储,单位是字节
ASCII码形式存储是5个字节
所以,二进制存储和ASCII码存储,会有大小上的差异,具体大小根据存储类型不同而不同。
比如如果是个字符型,ASCII码存储更小。
文件读取结束的判定
正确使用feof函数
不能在文件读取过程中使用feof函数来判断文件是否结束,而是在文件读取结束后,使用feof,搭载ferror共同使用,判断文件是因为读取结束而结束还是因为读取失败而结束。
使用读取函数时读取失败和读取结束返回值一样,要用feof和ferror来判断结束原因
文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
例如:
fgetc 判断是否为 EOF .
fgets 判断返回值是否为 NULL
二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
例如:
fread判断返回值是否小于实际要读的个数。
总结:博主认为在读取文件内容过程中判断条件应当与函数的返回值一一对应,特殊的fread返回值是实际读到的个数,每个大小为fread函数的第二个参数(以字节为单位),判断要读的和实际读到的是否相同,相同就不用feof(因为feof只能在读取结束后使用,相同并不代表读完了),不同就要判断结束原因,读取文件想知道读取是结束了还是读取失败了就可以向上方代码一样写if...else{if...else}。
文件缓冲区
编译器与磁盘进行输入输出操作时都有一个缓冲区,因为操作系统如果一直接收数据,会打乱操作系统,所以一个缓冲区充满,再更新数据,这样操作系统提高了效率。
ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。
由于以下代码进行测试是动态的,博主没有相关动图技术,所以不再演示。
#include <stdio.h>
#include <windows.h>
//VS2013 WIN10环境测试
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;
}
这里可以得出一个结论:
因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。
如果不做,可能导致读写文件的问题,比如内容在缓冲区中,断电就会失效,缓冲区的基本概念就是以上内容。
感谢代码玩家们的阅读,欢迎大家在评论区留言讨论,补充说明~