文本格式和二进制格式的区别

转自:http://jiadongkai-sina-com.iteye.com/blog/945854

一、理论分析

用C语言,经常碰到文件操作。关于二进制文件和文本文件,他们之间到底有什么不同呢?在这篇文章里,我用自己的方式来解读!不对之处,望各位牛人多指点,或联系我[email protected].
    我们都知道,在机器层面,所有的信息都是0/1,所有的信息都是通过0和1不同排列方式形成的。所以,信息不在于0和1这两个字符本身,而在于表示不同意思的这0和1两个符号的排列中所体现出的。我们都知道0和1在物理层面是脉冲的两种极值,如果在物理层面,可以显示区别的脉冲不止两个极值,而是多个值或者连续的值,这样在计算机的逻辑层面就不止0和1这两个符号了,可以有很多符号,于是,负好多了,他们排列组合的方式多了,信息的表达应该也更加高效和丰富了。
    上面一段,“信息”在机器层面是通过0和1的排列方式来体现的。可是这些0和1如何变成我们在windows环境下的记事本中看到的文本或者图片查看器中看到的图片呢?这里面就有一个编码的问题!所以,二进制文件和文本文件的不同就是编码层面的不同,二进制文件是值编码,如ASCII的文本文件文件是ASCII编码。文本编码可以是定长的(如作为基础的ASCII一个字符总是7位的,Unicode16位),也可以是不定长的(如UTF-8)。而值编码是不定长的(如BMP),它通过一定的读取规则来解释这些字节甚至一个bit就能包含一个信息。
     除了在内存和文件信息转存的时候有编码问题,在、
1、developer直接能看见的文本格式的源程序到内存的映射关系
2、从程序的内存到输出终端
这两个方面也同样存在编码转换问题!
     下面,我用一个图列出源程序(文本形式,如a.c)、内存、文件、输出终端这四方(其实输出终端、文件可以并在一起,都作为从内存中输出一类)之间编码转换的关系:



下面来解释这张图:
1、从“源程序”到“内存中”
在Java中"\r\n"等效于C中的"\n":java中中直接打印"\r\n"或者把这个字符串存进文件中用文本查看器打开都是换行的效果;在C中按文本文件的形式存,用文本查看器打开也是换行的效果,不过用二进制的形式存(保留内存中原来的格式),用文本查看器打开就会出现乱码码。
故,java中的"\r\n"和C中的"\n"在内存中都是“00001010”,所以在Java中有个转码,C中无需转码。
在源程序是字符的形式通过编码转码为内存的形式(这个编码格式是可以配置的),如果是整型或者浮点型等的也有固定的内存表示形式。
2、从“内存中”到“文件中”
看存储的格式,如果是二进制形式,数据原来在内存中怎么一个0和1排列,在文件的存储区域中还是同样的。
如果是文本格式,需要做些转码操作(如换行转为回车换行,整形数据由Turbo C++ 3.0环境下的占2Byte变为字符串的表现形式,可能就占用更多存储空间了);
3、从“文件中”到“内存中”
在C中fopen函数可以指定打开文件的形式(文本形式或者二进制的)。这两种形式的读取存在以下一些不同点:
二进制形式读取,不对文件的内存中的0和1的排列顺序做任何的调整,相当于文件存储空间和程序内存空间的之间平移;此时最小信息单位是位。也就是说一个bit就可以用来存储一个信息(如成功/失败)。我们需要在程序中对这些读进来的二进制数据按规则解析(如前两个byte可以组织成一个int类型数据等)。
文本格式读取,需要将回车换行符转换为换行符。此时最小信息单位是字节。
4、从“内存中”到“调试输出终端”
C中,一个int类型数据在内存中两个byte,要输出到终端,需要转换为文本格式的编码输出到指定的缓存,然后终端的解释器将这些字符串解释成一串字节显示在屏幕或者别的地方。


二、实验验证

    之前在思考二进制文件和文本文件的不同的时候,心想:有一个查看器,可以查看文件的二进制形式多好!
    于是,自己用c语言实现了一个在Doc命令行操作的“文件的二进制形式查看器”。这个查看器可以以文本方式和二进制方式两种方式读入文件,然后逐个自己打印出文件中的数据,打印的时候一个字节显示为八位1/0。也就说,我可以适合用这个查看器完成以下的功能:
1、以二进制形式查看文件----->可以知道数据在文件的存储空间中0/1的排列形式,直观的看出。
2、以文件形式查看文件------->可以知道文件读入函数都默认都做了哪些转码工作。如,回车换行转化为换行(在机器码层面就是:"0000110100001010"-->"00001010")

贴出所有的代码:
首先我自己创建了一个头文件:myhf.h
C代码  收藏代码
  1. #include <string.h>  
  2. char _str[17];/*多出的一个字符串表示字符串的结束*/  
  3. /* 
  4. 将一个字符的内存形式转化为字符串形式 
  5. 即'\n'-->"1010" 
  6. */  
  7. char * cTob(char c){  
  8.     unsigned i,a;  
  9.     i=c;/*直接将字符的内存拷贝到整型对应的内存中*/  
  10.     /*不管系统是高位补零还是补一,高位都清零*/  
  11.     a=~((~0)<<8);/*如果右移,因为是负数,这里是算数右移*/  
  12.     i=i&a;  
  13.     itoa(i,_str,2);/*整数i转化为二进制存在str数组中*/  
  14.     return _str;  
  15. }  

一个C源程序:
FileReader.c

程序可以配置文件读入方式1.文本2二进制
和读取文件的路径(绝对路径或相对路径)、
量个参数
配置好参数,自动组个字节打印文件中数据,每个字节间
空一格以便查看,每个字节打印8位,不足右对齐,多余位置用
空格表示
C代码  收藏代码
  1. /* 
  2. 一个读取和打印文本格式和二进制格式的应用程序 
  3. @author 贾懂凯@netjava 
  4. */  
  5. #include <stdio.h>  
  6. #include <string.h>  
  7. #include <myhf.h>  
  8. void main(){  
  9.   
  10.     void showTextFile(char[]);  
  11.     void showBinFile(char[]);  
  12.     char fileName[21];  
  13.     int fileFormat;  
  14.     /*1、用户确定需要解读的文件的格式*/  
  15.     printf("please input text formart:1text 2binary\n");  
  16.     scanf("%d",&fileFormat);  
  17.     /*2、用户给出文件的名字*/  
  18.     printf("please input file-name(len<20):\n");  
  19.       
  20.     scanf("%s",&fileName);  
  21.     /*3、根据用户需要解读的文件的格式判定调用哪个函数*/  
  22.     if(fileFormat==1){  
  23.         showTextFile(fileName);  
  24.     }else if(fileFormat==2){  
  25.         showBinFile(fileName);  
  26.     }  
  27.     printf("\n");  
  28.     printf("p:Print out the  data in the form of  memory representation (by-character printing, each person  with a single space between the characters, each character is eight less than equal amount of space)\n");  
  29. }  
  30.   
  31. /*将文本文件读入,打印到终端显示成二级乃至形式*/  
  32. void showTextFile(char name[21]){  
  33.     FILE * fp;/*一个在stdio.h文件中定义的对应一个文件的结构体数据*/  
  34.     fp=fopen(name,"r");  
  35.     while(!feof(fp)){/*直到文件读取结束*/  
  36.         char c=fgetc(fp);  
  37.         char * cp=cTob(c);/*转换成二进制形式的字符串形式*/  
  38.         printf("%8s ",cp);  
  39.     }  
  40.     fclose(fp);  
  41. }  
  42. /*将二进制文件读入,打印到终端显示成二级乃至形式*/  
  43. void showBinFile(char name[21]){  
  44.     FILE * fp;/*一个在stdio.h文件中定义的对应一个文件的结构体数据*/  
  45.     fp=fopen(name,"rb");  
  46.     while(!feof(fp)){/*直到文件读取结束*/  
  47.         char c=fgetc(fp);  
  48.         char * cp=cTob(c);/*转换成二进制形式的字符串形式*/  
  49.         printf("%8s ",cp);  
  50.     }  
  51.     fclose(fp);  
  52. }  



下面,我写了一个测试程序:
DemoFile.c

C代码  收藏代码
  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. /* 
  5. 测试文本文件和二进制文件的区别 
  6. 这里写入字符 "ab贾懂凯\na\r\na" 
  7. */  
  8. void main(){  
  9.     char s[]="ab贾懂凯\na\r\na";  
  10.     FILE * fp=fopen("a.txt","w");/*文本格式输出*/  
  11.     fprintf(fp,"%s",s);/*格式化输出到文件*/  
  12.       
  13.     fp=fopen("b.txt","wb");/*二进制格式输出*/  
  14.     fprintf(fp,"%s",s);/*格式化输出到文件*/  
  15. }  

先编译连接然后运行测试程序DemoFile.c,生成的两个文件截图:



然后,运行我写的&quot;文件的二进制形式查看器&quot;,doc命令行截图:



从这张doc命令行截图可以看出这个&quot;文件的二进制形式查看器&quot;打印出的0/1字符串的效果。这些字符串就是文件读入内存后的形式(在内存中0/1的排列方式这里如是打印出来了)。

到这里,对文本格式和二进制格式的区别。大家应该有一个比较深入和直观的印象了。其实,简单说,就是程序在内存、在硬盘空间或者在别的地方同一个东东有不同的表现形式而已,而这种表现形式的不同就是编码的不同造成的。当然,这篇文章里面并没有提到各种编码格式的优缺点,如二进制文件能够节省空间等等。有兴趣的朋友可以自己进一步探究!

补充:
上面解释的不是很清晰,参考这里http://wenku.baidu.com/view/d2b6a923dd36a32d7375810e.html
再给出清晰一点的定义:
所有的文件在内存和磁盘中都是二进制格式的,但由于解释这些01的编码方式不同,导致甚至同一串01都有不同的意义。不过,一般应保持写入和读取相同的编码方式。
所谓文本格式,指编码方式为UTF8等字符编码,最小的单位为byte
所谓二进制格式,指字符编码以外的编码方式,对文件中01的解释有其特有的一套规则,如BMP。当然,这种格式的文件使用window下的记事本(只支持字符编码)显然是乱码,BMP可用图片查看器解码。

另外,
C语言文件的读写,需要制定是文本格式还是二进制格式,区别是文本格式读入0000110100001010(\r\n)这个byte会变成00001010(\n),而二进制格式读入00001010依然是00001010。上面只对windows有效,在linux下\n在文本格式下写入文件也不变。

不知这样的理解有无偏差,望高手指点!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章