⽂本⽂件和⼆进制⽂件详解(转)
前⾔:
1)⽂本⽂件:这类⽂件以⽂本的ASCII码形式存储在计算机中。它是以”⾏”为基本结构的⼀种信息组织和存储⽅式。
2)⼆进制⽂件:这类⽂件以⽂本的⼆进制形式存储在计算机中,⽤户⼀般不能直接读懂它们,只有通过相应的软件才能将其显⽰出来。⼆进制⽂件⼀般是可执⾏程序、图形、图像、声⾳等等。
C++标准库提供了基于输⼊/输出流机制的⽂件操作,叫做⽂件流(File Stream)。打开⽂件的时候,可以⽤参数制定按照⼆进制⽅式还是⽂本⽅式。
ascii共有多少个字符
然⽽,可能与你的想象不同的是,这⾥的⼆进制或者⽂本与⽂件的格式并没有任何关系,⽽是⽂件流操作时对数据的表达⽅式。
⽂本⽅式和⼆进制⽅式的最⼤区别在于⽂本⽅式对于’\n’换⾏符的理解不同,在DOS平台下,该字符会被展开成< LF>两个控制字符(相当于”\r\n”),在ASCII字符集下是0DH,0AH,⽽在UNIX平台下,仅仅是,不会展开。⽽在⼆进制⽅式下,不管是什么平台,’\n’都是精确的。
⽽类似于⼀个数学上的数字128,会在⽂件中以什么样的格式存储,是以数字形式存储(80H),还是对应的可读⽂本
(‘1’,’2’,’8’),却和⽂件流的打开⽅式⽆关。
在C++的⽂件流中,使⽤的术语叫做格式化输⼊输出操作和⽆格式化操作,前者也就是<<;和>>运算符,将数字按照可读⽂本存储,后者是get/put成员函数,直接存储数字格式。
⼀、⽂本⽂件与⼆进制⽂件的定义
⼤家都知道计算机的存储在物理上是⼆进制的,所以⽂本⽂件与⼆进制⽂件的区别并不是物理上的,⽽是逻辑上的。这两者只是在编码层次上有差异。简单来说,⽂本⽂件是基于字符编码的⽂件,常见的编码有ASCII编码,UNICODE编码等等。⼆进制⽂件是基于值编码的⽂件,你可以根据具体应⽤,指定某个值是什么意思(这样⼀个过程,可以看作是⾃定义编码。
从上⾯可以看出⽂本⽂件基本上是定长编码的(也有⾮定长的编码如UTF-8)。⽽⼆进制⽂件可看成是变长编码的,因为是值编码嘛,多少个⽐特代表⼀个值,完全由你决定。⼤家可能对BMP⽂件⽐较熟悉,就拿它举例⼦吧,其头部是较为固定长度的⽂件头信息,前2字节⽤来记录⽂件为BMP格式,接下来的8个字节⽤来记录⽂件长度,再接下来的4字节⽤来记录bmp⽂件头的长度。
⼆、⽂本⽂件与⼆进制⽂件的存取
 ⽂本⼯具打开⼀个⽂件的过程是怎样的呢?拿记事本来说,它⾸先读取⽂件物理上所对应的⼆进制⽐特流,然后按照你所选择的解码⽅式来解释这个流,然后将解释结果显⽰出来。⼀般来说,你选取的解码⽅式会是ASCII码形式(ASCII码的⼀个字符是8个⽐特),接下来,它8个⽐特8个⽐特地来解释这个⽂件流。例如对于这么⼀个⽂件流”01000000_01000001_01000010_01000011”(下划
线”_”,为了增强可读性⼿动添加的),第⼀个8⽐特”01000000”按ASCII码来解码的话,所对应的字符是字符”A”,同理其它3个8⽐特可分别解码为”BCD”,即这个⽂件流可解释成“ABCD”,然后记事本就将这个“ABCD”显⽰在屏幕上。
事实上,世界上任何东西要与其他东西通信会话,都存在⼀个既定的协议,既定的编码。⼈与⼈之间通过⽂字联络,汉字“妈”代表⽣你的那个⼈,这就是⼀种既定的编码。但注意到这样⼀种情况,汉字“妈”在⽇本⽂字⾥有可能是你⽣下的那个⼈,所以当⼀个中国⼈A与⽇本B之间⽤“妈”这个字进⾏交流,出现误解就很正常的。⽤记事本打开⼆进制⽂件与上⾯的情况类似。记事本⽆论打开什么⽂件都按既定的字符编码⼯作(如ASCII码),所以当他打开⼆进制⽂件时,出现乱码也是很必然的⼀件事情了,解码和译码不对应嘛。例如⽂件流''00000000_00000000_00000000_00000001''可能在⼆进制⽂件中对应的是⼀个四字节的整数int 1,在记事本⾥解释就变成了"NULL_NULL_NULL_SOH"这四个控制符。
⽂本⽂件的存储与其读取基本上是个逆过程。⽽⼆进制⽂件的存取显然与⽂本⽂件的存取差不多,只是编/解码⽅式不同⽽已,也不再叙述。
三、⽂本⽂件与⼆进制⽂件的优缺点
因为⽂本⽂件与⼆进制⽂件的区别仅仅是编码上不同,所以他们的优缺点就是编码的优缺点,这个本编码的书来看看就⽐较清楚了。⼀般认为,⽂本⽂件编码基于字符定长,译码容易些;⼆进制⽂件编码是变长的,所以它灵活,存储利⽤率要⾼些,译码难⼀些(不同的⼆进制⽂件格式,有不同的译码⽅式)。关于空间利⽤率,想想看,⼆进制⽂件甚⾄可以⽤⼀个⽐特来代表⼀个意思(位操作),⽽⽂本⽂件任何⼀个意思⾄少是⼀个字符.
在windows下,⽂本⽂件不⼀定是⼀ASCII来存贮的,因为ASCII码只能表⽰128的标识,你打开⼀个txt⽂档,然后另存为,有个选项是编码,可以选择存贮格式,⼀般来说UTF-8编码格式兼容性要好⼀些.⽽⼆进制⽤的计算机原始语⾔,不存贮兼容性.    很多书上还认为,⽂本⽂件的可读性要好些,存储要花费转换时间(读写要编译码),⽽⼆进制⽂件可读性差,存储不存在转换时间(读写不要编解码,直接写值).这⾥的可读性是从软件使⽤者⾓度来说的,因为我们⽤通⽤的记事本⼯具就⼏乎可以浏览所有⽂本⽂件,所以说⽂本⽂件可读性好;⽽读写⼀个具体的⼆进制⽂件需要⼀个具体的⽂件解码器,所以说⼆进制⽂件可读性差,⽐如读BM P⽂件,必须⽤读图软件.
⽽这⾥的存储转换时间应该是从编程的⾓度来说的,因为有些操作系统如windows需要对回车换⾏符进⾏转换(将''\n'',换成''\r\n'',所以⽂件读写时,操作系统需要⼀个⼀个字符的检查当前字符是不是''\n''或''\r\n'').这个在存储转换在Linux操作系统中并不需要,当然,当在两个不同的操作系统上共享⽂件时,这种存储转换⼜可能出来(如Linux系统和Windows系统共享⽂本⽂件)。关于这个转换怎样进⾏,我将在下⼀篇⽂章《Linux⽂本⽂件与Windows⽂本⽂件间的转换》给出^_^
C的⽂本读写和⼆进制读写
应该说C的⽂本读写与⼆进制的读写是⼀个编程层次上的问题,与具体的操作系统有关,所以"⽤⽂本⽅式读写的⽂件⼀定是⽂本⽂件,⽤⼆进制读写的⽂件⼀定是⼆进制⽂件”这类观点是错误的.下⾯的讲述⾮明确指出操作系统类型,都暗指windows.
C的⽂本⽅读写与⼆进制读写的差别仅仅体现在回车换⾏符的处理上.⽂本⽅式写时,每遇到⼀个''\n''(0AH换⾏符),它将其换成''\r\n''(0D0AH,回车换⾏),然后再写⼊⽂件;当⽂本读取时,它每遇到⼀个''\r\n''将其反变化为''\n'',然后送到读缓冲区.正因为⽂本⽅式有''\n''--''\r\n''之间的转换,其存在转换耗时.⼆进制读写时,其不存在任何转换,直接将写缓冲区中数据写⼊⽂件.
总地来说,从编程的⾓度来说,C中⽂本或⼆进制读写都是缓冲区与⽂件中⼆进制流的交互,只是⽂本读写时有回车换⾏的转换.所以当写缓冲区中⽆换⾏符''\ n''(0AH),⽂本写与⼆进制写的结果是⼀样
的,同理,当⽂件中不存在''\r\n''(0DH0AH)时,⽂本读与⼆进制读的结果⼀样.
⽂本⽂件与⼆进制⽂件的区别:
将⽂件看作是由⼀个⼀个字节(byte) 组成的, 那么⽂本⽂件中的每个字节的最⾼位都是0,也就是说⽂本⽂件使⽤了⼀个字节中的七位来表⽰所有的信息,⽽⼆进制⽂件则是将字节中的所有位都⽤上了。这就是两者的区别;接着,第⼆个问题就是⽂件按照⽂本⽅式或者⼆进制⽅式打开,两者会有什么不同呢?其实不管是⼆进制⽂件也好,还是⽂本⽂件也好,都是⼀连串的0和1,但是打开⽅式不同,对于这些0和1的处理也就不同。如果按照⽂本⽅式打开,在打开的时候会进⾏translate,将每个字节转换成ASCII码,⽽以按照⼆进制⽅式打开的话,则不会进⾏任何的translate;最后就是⽂本⽂件和⼆进制⽂件在编辑的时候,使⽤的⽅式也是不同的。譬如,你在记事本中进⾏⽂本编辑的时候,你进⾏编辑的最⼩单位是字节(byte);⽽对⼆进制⽂件进⾏编辑的话,最⼩单位则是位(bit),当然我们都不会直接通过⼿⼯的⽅式对⼆进制⽂件进⾏编辑了。
从⽂件编码的⽅式来看,⽂件可分为ASCII码⽂件和⼆进制码⽂件两种:
ASCII⽂件也称为⽂本⽂件,这种⽂件在磁盘中存放时每个字符对应⼀个字节,⽤于存放对应的ASCII码。例如,数5678的存储形式为: ASCII码: 00110101 00110110 00110111 00111000
↓  ↓      ↓   ↓
⼗进制码: 5     6   7      8
共占⽤4个字节。ASCII码⽂件可在屏幕上按字符显⽰,例如源程序⽂件就是ASCII⽂件,⽤DOS命令TYPE可显⽰⽂件的内容。由于是按字符显⽰,因此能读懂⽂件内容。
⼆进制⽂件是按⼆进制的编码⽅式来存放⽂件的。例如,数5678的存储形式为:00010110 00101110 只占⼆个字节。⼆进制⽂件虽然也可在屏幕上显⽰,但其内容⽆法读懂。C系统在处理这些⽂件时,并不区分类型,都看成是字符流,按字节进⾏处理。输⼊输出字符流的开始和结束只由程序控制⽽不受物理符号(如回车符)的控制。因此也把这种⽂件称作“流式⽂件”。
⽂本模式(textmode)和⼆进制模式(binarymode)有什么区别?
流可以分为两种类型:⽂本流和⼆进制流。⽂本流是解释性的,最长可达255个字符,其中回车/换⾏将被转换为换⾏符“\n”,(如果以”⽂本”⽅式打开⼀个⽂件,那么在读字符的时候,系统会把所有的”\r\n”序列转成”\n”,在写⼊时把”\n”转成”\r\n” )。⼆进制流是⾮解释性的,⼀次处理⼀个字符,并且不转换字符。
注:
\n⼀般会操作系统被翻译成”⾏的结束”,即LF(Line-Feed)
\r会被翻译成”回车”,即CR(Cariage-Return)
对于⽂本⽂件的新⾏,在UNIX上,⼀般⽤\n(LF)来表⽰,Mac上⽤\r(CR)来表⽰,
Windows上是⽤\n\r(CR-LF)来表⽰。
通常,⽂本流⽤来读写标准的⽂本⽂件,或者将字符输出到屏幕或打印机,或者接受键盘的输⼊;⽽⼆进制流⽤来读写⼆进制⽂件(例如图形或字处理⽂档),或者读取⿏标输⼊,或者读写调制解调器。如果⽤⽂本⽅式打开⼆进制⽂件,会把“0D 0A”⾃动变换成“\n”来存在内存中。写⼊的时候反向处理。⽽⼆进制⽅式打开的话,就不会有这个过程。但是,Unicode/UTF/UCS格式的⽂件,必须⽤⼆进制⽅式打开和读写。