文件可以分为两类:二进制文件和字符(文本)文件。从物理上讲二进制文件和字符文件没有区别,都是以二进制的形式保存在磁盘上。但是它们在文件的组织形式上不一样,二进制文件有文件头(File Header),用以表明文件的大小、类型等信息,程序在处理二进制文件时一般会先分析文件头,判断文件是否合法,也就是说,文件头后面的数据才是程序真正要处理的;字符文件没有文件头,第一个字节就是要显示的内容。
拿 BMP 文件举例,其头部的长度较为固定,前2字节用来记录文件为BMP格式,接下来的8个字节用来记录文件长度,再接下来的4字节用来记录 BMP 文件头的长度。
文本文件是基于字符编码的,常见的编码方式有 ASCII、UNICODE、UTF-8 等;指定编码方式后,每个字节(也可以是每两个、三个字节)所表示的字符是一样的,任何程序都可以正确读取。
二进制文件是自定义编码的,也就是说,你可以根据具体程序指定每个字节(或者每两个、三个字节)代表什么意思。例如,A 程序是图像编辑器,指定 01001111 代表红色,B 程序是视频播放器,它把 01001111 理解为快进,显然是不对的。
所以,字符文件是通用的,任何程序只要按照对应的编码方式打开都可以正确显示,二进制文件只有特定的程序才能处理。
文本文件和二进制文件都可以在屏幕上显示,但是二进制文件的内容无法读懂,大部分是乱码。
在C语言中,二进制方式很简单,读文件时,会原封不动的读出文件的全部內容,写的時候,也是把內存缓冲区的內容原封不动的写到文件中。
而对文本文件的处理就不一样了。Windows 和 DOS 下的文本文件以CRLF(0X0D 0X0A)作为换行符,而C语言本身以LF(0X0A)作为换行符,所以以文本方式写入数据时,会将LF(0X0A)替换为CRLF(0X0D 0X0A),而读取数据时又会替换回来。
CR(0X0D)表示回车符,也就是 '\r';CL(0X0A)表示换行符,也就是 '\n'。
在Linux和其他一些系统中,文本文件的换行符就是LF(0X0A),与C语言的换行符一样。所以也就沒有了文本方式和二进制方式的区分,使不使用'b'标志都是一样的。
这是由于不同操作系统对文本文件换行符的定义,和C语言中换行符的定义有所不同而造成的。在Windows下,C语言的输入输出函数会自动进行 CRLF 和 LF 的转换,而Linux等就不必了。
另外,以文本方式打开时,遇到结束符CTRLZ(0x1A)就认为文件已经结束。所以,若使用文本方式打开二进制文件,就很容易出现文件读不完整,或內容不对的错误。即使是用文本方式打开文本文件,也要谨慎使用,比如复制文件,就不应该使用文本方式。
综上所述:二进制和文本模式的区别就在于对换行符和一些非可见字符的转化上,如非必要,是使用二进制读取会比较安全一些。