文本格式和二進制格式的區別

轉自: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在文本格式下寫入文件也不變。

不知這樣的理解有無偏差,望高手指點!

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