1. 程式人生 > >彭令鵬(bripengandre)的專欄

彭令鵬(bripengandre)的專欄

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

一、文字檔案與二進位制檔案的定義

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

       簡單來說,文字檔案是基於字元編碼的檔案,常見的編碼有ASCII編碼,UNICOD
E編碼等等。二進位制檔案是基於值編碼的檔案,你可以根據具體應用,指定某個值是什麼
意思(這樣一個過程,可以看作是自定義編碼)。

       從上面可以看出文字檔案基本上是定長編碼的,基於字元嘛,每個字元在具體編
碼中是固定的,ASCII碼是8個位元的編碼,UNICODE一般佔16個位元。而二進位制檔案可看
成是變長編碼的,因為是值編碼嘛,多少個位元代表一個值,完全由你決定。大家可能
對BMP檔案比較熟悉,就拿它舉例子吧,其頭部是較為固定長度的檔案頭資訊,前2位元組
用來記錄檔案為BMP格式,接下來的8個位元組用來記錄檔案長度,再接下來的4位元組用來記
錄bmp檔案頭的長度。。。大家可以看出來了吧,其編碼是基於值的(不定長的,2、4、
8位元組長的值都有),所以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_NU
LL_SOH"這四個控制符。

  文字檔案的儲存與其讀取基本上是個逆過程,不再累述。而二進位制檔案的存取顯然
與文字檔案的存取差不多,只是編/解碼方式不同而已,也不再敘述。

  

三、文字檔案與二進位制檔案的優缺點

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

  很多書上還認為,文字檔案的可讀性要好些,儲存要花費轉換時間(讀寫要編譯碼)
,而二進位制檔案可讀性差,儲存不存在轉換時間(讀寫不要編解碼,直接寫值).這裡
的可讀性是從軟體使用者角度來說的,因為我們用通用的記事本工具就幾乎可以瀏覽所
有文字檔案,所以說文字檔案可讀性好;而讀寫一個具體的二進位制檔案需要一個具體的
檔案解碼器,所以說二進位制檔案可讀性差,比如讀BMP檔案,必須用讀圖軟體.而這裡的
儲存轉換時間應該是從程式設計的角度來說的,因為有些作業系統如windows需要對回車換行
符進行轉換(將'/n',換成'/r/n',所以檔案讀寫時,作業系統需要一個一個字元的檢查
當前字元是不是'/n'或'/r/n').這個在儲存轉換在Linux作業系統中並不需要,當然,當
在兩個不同的作業系統上共享檔案時,這種儲存轉換又可能出來(如Linux系統和Window
s系統共享文字檔案)。關於這個轉換怎樣進行,我將在下一篇文章《Linux文字檔案與W
indows文字檔案間的轉換》給出^_^

四、C的文字讀寫和二進位制讀寫

  應該說C的文字讀寫與二進位制的讀寫是一個程式設計層次上的問題,與具體的作業系統
有關,所以"用文字方式讀寫的檔案一定是文字檔案,用二進位制讀寫的檔案一定是二進
制檔案"這類觀點是錯誤的.下面的講述非明確指出作業系統型別,都暗指windows.

  C的文字方讀寫與二進位制讀寫的差別僅僅體現在回車換行符的處理上.文字方式寫
時,每遇到一個'/n'(0AH換行符),它將其換成'/r/n'(0D0AH,回車換行),然後再寫入
檔案;當文字讀取時,它每遇到一個'/r/n'將其反變化為'/n',然後送到讀緩衝區.正
因為文字方式有'/n'--'/r/n'之間的轉換,其存在轉換耗時.二進位制讀寫時,其不存
在任何轉換,直接將寫緩衝區中資料寫入檔案.

   總地來說,從程式設計的角度來說,C中文字或二進位制讀寫都是緩衝區與檔案中二進
制流的互動,只是文字讀寫時有回車換行的轉換.所以當寫緩衝區中無換行符'/n'(0AH
),文字寫與二進位制寫的結果是一樣的,同理,當檔案中不存在'/r/n'(0DH0AH)時,文字
讀與二進位制讀的結果一樣.

   下面給出一個小程式來證明前面的觀點.

1、編寫如下程式.該程式將字串"12/n3"分別以文字方式和二進位制方式寫入test1和t
est2,然後再以文字方式

讀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                           //二進位制方式讀test1,讀到的字元與原先寫入test1
的字元一樣

  3.用記事本開啟test1和test2,結果如下:

  test1的內容:

 12

  3           //文字方式寫入的,有換行效果,參看下面的4

  test2的內容

  123         //二進位制方式寫入的,無換行效果(記事本對"/r/n"之外的控制字串無
顯示效果),參看下面的4

4、用vc6.0以Binary方式(二進位制方式)開啟test1和test2,結果如下(用其他二進位制讀
寫軟體也可以) 

  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,在linux中文字方式的讀寫與二進位制方式的讀寫無差
別,不存在回車換行間的轉換.這樣當直接在windows和linux中共享檔案時,將會出現
與回車換行相關的問題.下一篇文章《Linux文字檔案與Windows文字檔案間的轉換》將
給出Linux文字檔案與Windows文字檔案間轉換的C程式,敬請關注^_^