文本文件與二進製文件的編碼差別
網上關於文本文件與二進製文件的文章很多,但遺憾的是,這些文章講得都比較散。下麵我將結合所查到的資料,從多個角度談談文本文件與二進製文件。
一、文本文件與二進製文件的定義
大家都知道計算機的存儲在物理上是二進製的,所以文本文件與二進製文件的區別並不是物理上的,而是邏輯上的。這兩者隻是在編碼層次上有差異。
簡單來說,文本文件是基於字符編碼的文件,常見的編碼有ASCII編碼,UNICODE編碼等等。二進製文件是基於值編碼的文件,可以根據具體應用,指定某個值是什麼意思(這樣一個過程,可以看作是自定義編碼)。
從上麵可以看出文本文件基本上是定長編碼的,基於字符,每個字符在具體編碼中是固定的,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_NULL_SOH"這四個控製符。
文本文件的存儲與其讀取基本上是個逆過程,不再贅述。而二進製文件的存取顯然與文本文件的存取差不多,隻是編解碼方式不同而已,也不再敘述。
三、文本文件與二進製文件的優缺點
因為文本文件與二進製文件的區別僅僅是編碼上不同,所以他們的優缺點就是編碼的優缺點,這個找本編碼的書來看看就比較清楚了。一般認為,文本文件編碼基於字符定長,譯碼容易些;二進製文件編碼是變長的,所以它靈活,存儲利用率要高些,譯碼難一些(不同的二進製文件格式,有不同的譯碼方式)。關於空間利用率,想想看,二進製文件甚至可以用一個比特來代表一個意思(位操作),而文本文件任何一個意思至少是一個字符.
很多書上還認為,文本文件的可讀性要好些,存儲要花費轉換時間(讀寫要編譯碼), 而二進製文件可讀性差,存儲不存在轉換時間(讀寫不要編解碼,直接寫值)。這裏的可讀性是從軟件使用者角度來說的,因為我們用通用的記事本工具就幾乎可以瀏覽所有文本文件,所以說文本文件可讀性好;而讀寫一個具體的二進製文件需要一個具體的文件解碼器,所以說二進製文件可讀性差,比如讀bmp文件,必須用讀圖軟件。而這裏的存儲轉換時間應該是從編程的角度來說的,因為有些操作係統如Windows需要對回車換行符進行轉換(將''/n'',換成''/r/n'',所以文件讀寫時,操作係統需要一個一個字符的檢查當前字符是不是''/n''或''/r/n'').這個在存儲轉換在Linux操作係統中並不需要,當然,當在兩個不同的操作係統上共享文件時,這種存儲轉換又可能出來(如Linux係統和Windows係統共享文本文件)。
四、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和test2,然後再以文本方式讀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、用記事本打開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,在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