文本文件和二进制文件到底有什么区别?
在学习C语言fopen()函数后,知道它的第二个参数是读取方式字符串。如果字符串中出现'b',则表明是以二进制(binary)方式读取,否则是以文本方式读取。
文本文件和二进制文件的本质区别
文件可以分为两类:二进制文件和字符(文本)文件。
从物理上讲,二进制文件和字符文件没有区别,都是以二进制的形式保存在磁盘上。
但是它们在文件的组织形式上不一样,
二进制文件有文件头(File Header),用以表明文件的大小、类型等信息,程序在处理二进制文件时一般会先分析文件头,判断文件是否合法,也就是说,文件头后面的数据才是程序真正要处理的;拿 BMP 文件举例,其头部的长度较为固定,前2字节用来记录文件为BMP格式,接下来的8个字节用来记录文件长度,再接下来的4字节用来记录 BMP 文件头的长度。
字符文件没有文件头,第一个字节就是要显示的内容。
文本文件是基于字符编码的,(个人:字符存储到文件时,根据使用的字符集找到这个字符在这个字符集中的字符值,然后根据指定的编码方式将这个字符值编码为二进制字节形式存储到文件中),常见的编码方式有 ASCII、UNICODE、UTF-8 等;指定编码方式后,每个字节(也可以是每两个、三个字节)所表示的字符是一样的,任何程序都可以正确读取。二进制文件是自定义编码的,也就是说,你可以根据具体程序指定每个字节(或者每两个、三个字节)代表什么意思。例如,A 程序是图像编辑器,指定 01001111 代表红色,B 程序是视频播放器,它把 01001111 理解为快进,显然是不对的。所以,字符文件是通用的,任何程序只要按照对应的编码方式打开都可以正确显示,二进制文件只有特定的程序才能处理。
文本文件通常用来保存肉眼可见的字符,比如.txt文件、.c文件、.dat文件等,用文本编辑器按照正确的编码方式打开这些文件,我们能够顺利看懂文件的内容。 二进制文件通常用来保存视频、图片、程序等不可阅读的内容,用文本编辑器打开这些文件,会看到一堆乱码,根本看不懂。(个人:我们之所以能看懂文本文件的内容,是因为文本文件中采用的是 ASCII、UTF-8、GBK 等字符编码,文本编辑器指定对应的编码方式后,可以解析出字符值(字符在字符集中的index),进而根据字符集映射成字符展示出来)。 而二进制文件使用的是 mp4、gif、exe 等特殊编码格式,文本编辑器并不认识这些编码格式,只能按照字符编码格式胡乱解析,所以就成了一堆乱七八糟的字符,有的甚至都没见过。总起来说,不同类型的文件有不同的编码格式,必须使用对应的程序(软件)才能正确解析,否则就是一堆乱码,或者无法使用。
fopen中的文本读取方式和二进制读取方式
在C语言中,二进制方式很简单,
读文件时,会原封不动的读出文件的全部內容,(个人:文件中的内容也就是01序列)
写的時候,也是把內存缓冲区的內容原封不动的写到文件中。(个人:内存缓冲区的内容也是01序列)
而对文本方式的处理就不一样了,
Windows和DOS下的文本文件以'\r\n'(0X0D 0X0A)作为换行符,而C语言本身以'\n'(0X0A)作为换行符,(0x0D(asc码是13) 即'\r',指的是“回车” ,是把光标置于本行行首。 0x0A(asc码是10) 即'\n',指的是“换行” \n是把光标置于下一行的同一列。 0x0D + 0x0A ,即'\r\n',回车换行,把光标置于下一行行首 。 \n是换行,英文是linefeed,ASCII码是0xA。\r是回车,英文是carriage return ,ASCII码是0xD),所以,
以文本方式写入数据时,会将'\n'(0X0A)替换为'\r\n'(0X0D 0X0A),
而读取数据时又会替换回来。
在Linux和其他一些系统中,文本文件的换行符就是'\n'(0X0A),与C语言的换行符一样。所以也就沒有了文本方式和二进制方式的区分,使不使用'b'标志都是一样的。(个人:既然Linux下二者没有区别,那么读取或者写入的行为应该是相同的),这是由于不同操作系统对文本文件换行符的定义,和C语言中换行符的定义有所不同而造成的。在Windows下,C语言的输入输出函数会自动进行 '\r\n'和 '\n'的转换,而Linux等就不必了。(个人:例如printf函数,会将内存中的'\n'转换为'\r\n',然后打印到屏幕上)
另外,以文本方式打开时,遇到结束符CTRLZ(0x1A)就认为文件已经结束。所以,若使用文本方式打开二进制文件,就很容易出现文件读不完整,或內容不对的错误。即使是用文本方式打开文本文件,也要谨慎使用,比如复制文件,就不应该使用文本方式。
综上所述:C语言中fopen()函数二进制和文本模式的区别就在于对换行符和一些非可见字符的转化上,如非必要,是使用二进制读取会比较安全一些。(个人:二进制读取时原汁原味,没有额外的转化,注意,这里是c语言中fopen()函数的二进制和文本模式的区别,而不是广义的通常意义上的二进制文件和文本文件的区别)
上一节同样的例子,我们现在使用二进制方式读取,
(个人:应该是我们读取的内容保存到char str[N+1]中,因此对于读取的内容解释成char,个人猜测c语言里的fopen函数无论文本方式还是二进制方式,读取的都是字节序列,根据将读取出来的字节序列放到什么类型的变量里,来具体的解释读取处理的字节序列,还有,c语言是接近底层的语言,猜测c语言读写文件时,可能是操作的对象都是原始的字节,)