我们知道fopen函数的第二个参数是文件的读写方式,r w为文本文件读写,rb wb为二进制文件读写。简单看下文本文件和二进制文件的区别。
一般说,文本文件是基于字符编码的文件,二进制文件是基于值编码的文件。但也不尽其然。
首先看,文本工具打开一个文件的过程。拿记事本来说,它首先读取文件物理上所对应的二进制比特流(前面已经说了,存储都是二进制的),然后按照你所选择的解码方式来解释这个流,然后将解释结果显示出来。一般来说,你选取的解码方式会是ASCII码形式(ASCII码的一个字符是8个比特),接下来,它8个比特8个比特地来解释这个文件流。例如对于这么一个文件流"01000000_01000001_01000010_01000011"(下划线'_',是我为了增强可读性,而手动添加的),第一个8比特'01000000'按ASCII码来解码的话,所对应的字符是字符'A',同理其它3个8比特可分别解码为'BCD',即这个文件流可解释成“ABCD”,然后记事本就将这个“ABCD”显示在屏幕上。
文本文件,二进制文件,其存储与其读取都是逆过程,差不多,不同的是编/解码方式。
二进制文件是将内存中数据原封不动的传至文件中,保存的是从0到0xff(0到255)不等的字节值,是按字节存储的,所以二进制文件模式下,数据在内存的大小与其在文件中的大小完全一至。
而windows下C的文本方读写与二进制读写的差别,其中之一体现在回车换行符的处理上。文本方式写时,每遇到一个'\n'(0AH换行符),它将其换成'\r\n'(0D0AH,回车换行),然后再写入文件;当文本读取时,它每遇到一个'\r\n'将其反变化为'\n',然后送到读缓冲区。所以文本文件模式下,数据在内存的大小与文件中的大小不完全一至。
在现在的术语中,通常将二进制文件称为包含了字节的字符流,大多数语言倾向于将其理解为字符流而不是文件。
看个例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma pack(1)
struct info{
int a;
int b;
char str[100];
};
#pragma pack()
int main()
{
FILE *fp_text,*fp_binary;
struct info data = {10,9,"我们11\n2"};
fp_text=fopen("test1","wt+");
fp_binary=fopen("test2","wb+");
fwrite(&data, sizeof(data),1,fp_text);
fwrite(&data, sizeof(data),1,fp_text);
fwrite(&data, sizeof(data),1,fp_binary);
fwrite(&data, sizeof(data),1,fp_binary);
int len = sizeof(data);
fseek(fp_text,len+2,SEEK_SET);
fseek(fp_binary,len,SEEK_SET);
struct info read_data_t;
struct info read_data_b;
fread(&read_data_t, sizeof(data), 1, fp_text);
fread(&read_data_b, sizeof(data), 1, fp_binary);
printf("a = %d b = %d str = %s\n", read_data_t.a, read_data_t.b, read_data_t.str);
printf("a = %d b = %d str = %s\n", read_data_b.a, read_data_b.b, read_data_b.str);
fclose(fp_text);
fclose(fp_binary);
return 0;
}
结果:
a = 10 b = 9 str = 我们11
2
a = 10 b = 9 str = 我们11
2
程序中 fseek(fp_text,len+2,SEEK_SET);
fseek(fp_binary,len,SEEK_SET);
可以看出,fp_text放到了距离文件头len+2个字节的位置,而pf_binary放到了距离文件头len个字节的位置,打印出来的结果都是第二个保存的data。
说明了文本模式下,数据在内存的大小与文件中的大小不完全一致。
也说明了二进制文件可以随机读取,而文本文件只能顺序读取。