閱讀780 返回首頁    go 阿裏雲 go 技術社區[雲棲]


文本文件與二進製文件的編碼差別

網上關於文本文件與二進製文件的文章很多,但遺憾的是,這些文章講得都比較散。下麵我將結合所查到的資料,從多個角度談談文本文件與二進製文件。


一、文本文件與二進製文件的定義

       大家都知道計算機的存儲在物理上是二進製的,所以文本文件與二進製文件的區別並不是物理上的,而是邏輯上的。這兩者隻是在編碼層次上有差異。

       簡單來說,文本文件是基於字符編碼的文件,常見的編碼有ASCII編碼,UNICODE編碼等等。二進製文件是基於值編碼的文件,可以根據具體應用,指定某個值是什麼意思(這樣一個過程,可以看作是自定義編碼)。

       從上麵可以看出文本文件基本上是定長編碼的,基於字符,每個字符在具體編碼中是固定的,ASCII碼是8個比特的編碼,UNICODE一般占16個比特。而二進製文件可看成是變長編碼的,因為是值編碼,多少個比特代表一個值,完全由自定義決定。大家可能對bmp文件比較熟悉,就拿它舉例子吧,其頭部是固定長度的文件頭信息,前2字節用來記錄文件為BMP格式,接下來的8個字節用來記錄文件長度,再接下來的4字節用來記錄bmp文件頭的長度。大家可以看出來,其編碼是基於值的(不定長的,248字節長的值都有),所以BMP是二進製文件。


二、文本文件與二進製文件的存取

       文本工具打開一個文件的過程是怎樣的呢?拿記事本來說,它首先讀取文件物理上所對應的二進製比特流(前麵已經說了,存儲都是二進製的),然後按照所選擇的解碼方式來解釋這個流,然後將解釋結果顯示出來。一般來說,你選取的解碼方式會是ASCII碼形式(ASCII碼的一個字符是8個比特),接下來,它8個比特8個比特地來解釋這個文件流。例如對於這麼一個文件流"01000000_01000001_01000010_01000011"(下劃線”_”,是我為了增強可讀性,而手動添加的),第一個8比特''01000000''ASCII碼來解碼的話,所對應的字符是字符''A'',同理其它38比特可分別解碼為''BCD'',即這個文件流可解釋成"ABCD",然後記事本就將這個"ABCD"顯示在屏幕上。

       事實上,世界上任何東西要與其他東西通信會話,都存在一個既定的協議,既定的編碼規範。人與人之間通過文字聯絡,如在漢語中,漢字代表生育你的那個人,這就是一種既定的編碼。但注意到這樣一種情況,漢字在日本文字裏有可能是你生育下的那個人,所以當一個中國人A與日本人B之間用這個字進行交流,出現誤解就很正常的。用記事本打開二進製文件與上麵的情況類似。記事本無論打開什麼文件都按既定的字符編碼工作(如ASCII碼),所以當他打開二進製文件時,出現亂碼也是很必然的一件事情了,原因就在於解碼和譯碼不對應。例如文件流''00000000_00000000_00000000_00000001''可能在二進製文件中對應的是一個四字節的整數int 1,但在記事本裏解釋就變成了"NULL_NULL_NULL_SOH"這四個控製符。

       文本文件的存儲與其讀取基本上是個逆過程,不再贅述。而二進製文件的存取顯然與文本文件的存取差不多,隻是編解碼方式不同而已,也不再敘述。


三、文本文件與二進製文件的優缺點

       因為文本文件與二進製文件的區別僅僅是編碼上不同,所以他們的優缺點就是編碼的優缺點,這個找本編碼的書來看看就比較清楚了。一般認為,文本文件編碼基於字符定長,譯碼容易些二進製文件編碼是變長的,所以它靈活,存儲利用率要高些,譯碼難一些(不同的二進製文件格式,有不同的譯碼方式)。關於空間利用率,想想看,二進製文件甚至可以用一個比特來代表一個意思(位操作),而文本文件任何一個意思至少是一個字符.

       很多書上還認為,文本文件的可讀性要好些,存儲要花費轉換時間(讀寫要編譯碼), 而二進製文件可讀性差,存儲不存在轉換時間(讀寫不要編解碼,直接寫值)。這裏的可讀性是從軟件使用者角度來說的,因為我們用通用的記事本工具就幾乎可以瀏覽所有文本文件,所以說文本文件可讀性好;而讀寫一個具體的二進製文件需要一個具體的文件解碼器,所以說二進製文件可讀性差,比如讀bmp文件,必須用讀圖軟件。而這裏的存儲轉換時間應該是從編程的角度來說的,因為有些操作係統如Windows需要對回車換行符進行轉換(''/n'',換成''/r/n'',所以文件讀寫時,操作係統需要一個一個字符的檢查當前字符是不是''/n''''/r/n'').這個在存儲轉換在Linux操作係統中並不需要,當然,當在兩個不同的操作係統上共享文件時,這種存儲轉換又可能出來(Linux係統和Windows係統共享文本文件)


四、C的文本讀寫和二進製讀寫

       應該說C的文本讀寫與二進製的讀寫是一個編程層次上的問題,與具體的操作係統有關,所以“用文本方式讀寫的文件一定是文本文件,用二進製讀寫的文件一定是二進製文件”這類觀點是錯誤的。下麵的講述非明確指出操作係統類型,都暗指WindowsC的文本方讀寫與二進製讀寫的差別僅僅體現在回車換行符的處理上。文本方式寫時,每遇到一個''/n''(0AH換行符),它將其換成''/r/n''(0D0AH,回車換行),然後再寫入文件;當文本讀取時,它每遇到一個''/r/n''將其反變化為''/n'',然後送到讀緩衝區。正因為文本方式有''/n''--''/r/n''之間的轉換,其存在轉換耗時。二進製讀寫時,其不存在任何轉換,直接將寫緩衝區中數據寫入文件。

總地來說,從編程的角度來說,C中文本或二進製讀寫都是緩衝區與文件中二進製流的交互,隻是文本讀寫時有回車換行的轉換。所以當寫緩衝區中無換行符''/n''(0AH),文本寫與二進製寫的結果是一樣的,同理,當文件中不存在''/r/n''(0DH0AH)時,文本讀與二進製讀的結果一樣。


下麵給出一個小程序來證明前麵的觀點。

1、編寫如下程序。該程序將字符串"12/n3"分別以文本方式和二進製方式寫入test1test2,然後再以文本方式讀test1,以二進製方式讀test2。

#include<stdio.h>
int main()
{
    FILE * fp_text,* fp_binary;
    char write_buf[4]={'1','2','/n','3'};
    char read_buf_text[6],read_buf_binary[6];
    int read_count_text,read_count_binary;
    //未檢測打開是否失敗
    fp_text=fopen("test1","wt+");
    fp_binary=fopen("test2","wb+");
    fwrite(write_buf,4,1,fp_text);
    fwrite(write_buf,4,1,fp_binary);
    //fflush(fp_text);
    //fflush(fp_binary);
 
    fseek(fp_text,0L,SEEK_SET);//fseek附帶了fflush功能
    fseek(fp_binary,0L,SEEK_SET);
    read_count_text=fread(read_buf_text,sizeof(char),5,fp_text);
    read_count_binary=fread(read_buf_binary,sizeof(char),5,fp_binary);
    //加''/0'',便於打印字符串
    read_buf_text[read_count_text]='/0';
    read_buf_binary[read_count_binary]='/0';
    printf("In Text Mode:read_count=%d,string=%s/n",read_count_text,read_buf_text);
    printf("In Binary Mode:read_count=%d,string=%s/n",read_count_binary,read_buf_binary);
    fclose(fp_text);
    fclose(fp_binary);     
    return 0; 
}

2、該程序在VC6.0下編譯運行,顯示結果如下

In Text Mode:read_count=4,string=12
3                           
//文本方式讀test1,讀到的字符與原先寫入test1的字符一樣
In Binary Mode:read_count=4,string=12
3                           
//二進製方式讀test2,讀到的字符與原先寫入test2的字符一樣

3、用記事本打開test1test2,結果如下:

test1的內容:
12
3           
//文本方式寫入的,有換行效果,參看下麵的4
test2的內容:
123         
//二進製方式寫入的,無換行效果(記事本對"/r/n"之外的控製字符串無顯示效果),參看下麵的4

4、用vc6.0Binary方式(二進製方式)打開test1test2,結果如下(用其他二進製讀寫軟件也可以) 

test1的內容:
31 32 0D 0A 33
//十六進製,5個字節,比寫入緩衝區多了一個字節,在"/n"(0AH)前插了一個"/r"(0DH)
test2的內容:
31 32 0A 33
//十六進製,4個字節,與寫入緩衝區的值一致

5、總結

    從4可以看出,文本方式寫時,存在''/n''->''/r/n''的轉換,而二進製方式無轉換。又從2和4可以推出文本方式讀時存在''/r/n''->''/n''的轉換,而二進製方式無轉換。有興趣的讀者可以嚐試以二進製方式讀test1或以文本方式讀test2,看會出現什麼效果。

6.補充說明

上述說明僅適用於Windows,在Unix/Linux中文本方式的讀寫與二進製方式的讀寫無差別,不存在回車換行間的轉換。UNIX/Linux並沒有區分這兩種文件,他們對所有文件一視同仁,將所有文件都看成二進製文件。標準I/O庫中 主要使用 fread/fwrite來讀寫二進製文件,而對於文本文件可以使用 fread/fwrite/fgetc/fputc fprintf等等。


轉載地址:https://blog.csdn.net/do2jiang/article/details/5863135

最後更新:2017-04-03 05:39:29

  上一篇:go Web服務
  下一篇:go 瀏覽器開發人員工具