C|文本文件的文本、二進制存儲以及回車符和換行符的處理

C/C++中對文件的操作分以二進制文件方式讀寫和以文本文件方式讀寫兩種(這裡說的是文本文件,對於圖像、音頻文件,自然是以二進制處理)。例如,

<code>/*以讀方式打開文本文件*/
FILE *fp = fopen("test.txt","r");
/*以寫方式打開二進制文件*/
FILE *fp = fopen("test.txt","wb");/<code>

對於文本,處理的內容包括字符、數字。

對於數字,二進制存儲自然是將整數用補碼的方案,而浮點數是以IEE754的編碼方案。數字用文本方式存儲,要將單個數字轉換為ASCII編碼。

對於字符,二者的區別在於對換行符的處理上,不同的操作系統有所區別,其它字符的存儲都是一樣的。

1 回車符和換行符

回車符 Carrier Return (CR):’\r’,對應ASCII的13,功能:將打字機頭定位在左邊界。

換行符 Line Feed (LF):’\n’, 對應ASCII的10,功能:打字機把紙下移一行。

在計算機還沒有出現之前,有一種叫做電傳打字機(Teletype Model 33)的玩意,每秒鐘可以打10個字符。但是它有一個問題,就是打完一行換行的時候,要用去0.2秒,正好可以打兩個字符。要是在這0.2秒裡面,又有新的字符傳過來,那麼這個字符將丟失。

於是,研製人員想了個辦法解決這個問題,就是在每行後面加兩個表示結束的字符。一個叫做“回車”,告訴打字機把打印頭定位在左邊界;另一個叫做“換行”,告訴打字機把紙向下移一行。

這就是“換行”和“回車”的來歷,從它們的英語名字上也可以看出一二。

後來,計算機發明瞭,這兩個概念也就被般到了計算機上。那時,存儲器很貴,一些科學家認為在每行結尾加兩個字符太浪費了,加一個就可以。於是,就出現了分歧。

Unix 系統裡,每行結尾只有“”,即“\n”;Windows系統裡面,每行結尾是“ ”,即“\r\n”;Mac系統裡,每行結尾是“”。一個直接後果是,Unix/Mac系統下的文件在Windows裡打 開的話,所有文字會變成一行;而Windows裡的文件在Unix/Mac下打開的話,在每行的結尾可能會多出一個^M符號。

現在這兩個功能完全沒必要分,我們通常所說的“換行”都是指:光標移動到行首+光標移動到下一行。

文本文件的行結束符,windows系統用’\r\n’;Mac系統用’\r’;Unix系統用’\n’。

2 C語言windows平臺下,處理二進制文件和文本文件的區別

不同計算機上c語言統一規定為:

文本文件的行結束符一律是一個符號LF,也就是換行符,也就是new line符或’\n’。但在windows平臺下,以文本文件方式讀入到磁盤存儲器中,就有所區別了。

2.1 讀寫文本文件

在向文本文件寫入’\n’時,實際上寫入了’\r\n’(因為windows平臺用’\r\n’表示換行)保存到了磁盤文件;

從文本文件讀到換行時(’\r\n’)會自動將’\r’捨去,只保留’\n’讀入到內存。

例如,執行下面的代碼,

<code>FILE *fp = fopen("test.txt","w+");
fprintf(fp, "abc\ndef");/*寫入7個字符*//<code>

得到的文件大小為8字節,用winhex打開結果為:

可以看到文件裡有8個字符,包括ASCII碼為0x0D的’\r’和0x0A的’\n’。

同理,重新打開這個文件進行讀取,會發現無法讀取到’\r’字符只能讀到’\n’。

2.2 讀寫二進制文件

寫二進制文件,寫入的是什麼就是什麼,並不會增加任何東西。

例如,執行下面的代碼,

<code>FILE *fp = fopen("test.txt","wb+");
fprintf(fp, "abc\ndef");/*寫入7個字符*//<code>

得到的文件大小為7字節,用winhex打開結果為:

可以看到文件裡僅有寫入的7個字符。

同理,讀二進制文件,讀到的是什麼就是什麼,並不會捨去任何東西。例如,打開3.1中的文件,是可以同時讀到’\r’字符和’\n’字符的。

2.3 總結一下:

windows系統下,讀寫文本文件都要對換行符做特殊處理,而讀寫二進制文件則不需要。

C語言中,讀寫文本文件用fprintf()和fscanf()等函數,這兩個函數會默認處理的數據都是ASCII碼;讀寫二進制文件用fwrite()和fread()函數。

寫文本文件,將內存中的數字做轉換,換行符做處理,再寫入到文本中。 而寫二進制文件,則是將內存裡面的數值直接寫入磁盤的文本中。

文本文件是為了讓人閱讀;二進制文件是為了讓機器閱讀。

一般情況下二進制文件佔用空間更小,計算機處理更快。例如,保存整數1144201745(4個字節的int)。

以文本文件方式存儲:

<code>int num = 1144201745;
FILE *fp = fopen("test.txt","w+");
fprintf(fp, "%d", num);/*十進制方式寫入*//<code>

得到的文件大小為10字節:num有10位。

可看到,內存中存儲的是num各位的ASCII碼。

以二進制方式存儲:

<code>int num = 1144201745;
FILE *fp = fopen("test.txt","wb+");
fprintf(fp, "%d", num);/*十進制方式寫入*//<code>

得到的文件大小為4字節:num是int只佔4字節。

可以看到,內存中存儲的是num的二進制表示。

2.4 文件位置操作:seeking和telling

由上述內容可知,對文本存儲方式數字和換行的特殊處理,文本文件在內存中的數據表示與磁盤上數據表示的長度不同,文本文件中的seeking和telling是不可靠動作(包括UI的文本框內文本的操作)。當程序需要在文件內查找和告知當前文件的位置,程序應該使用二進制模式打開文件。

3 按下Enter鍵,讀取字符函數讀到什麼

鍵盤上的enter鍵對應的字符是’\r’,而enter鍵還有額外很多功能,例如,將控制檯輸入寫入緩衝區,並將’\n’寫入緩衝區。

<code>#include 
ch=getch();      // 從鍵盤上讀入一個字符不回顯直接(不需回車)送給字符變量ch
ch=getche();    // 從鍵盤上讀入一個字符帶回顯直接(不需回車)送給字符變量ch
#include 
ch=getchar()   // 從鍵盤上讀入一個字符帶回顯         (需回車)送給字符變量ch
cout

使用getch(), getche()獲取鍵盤輸入時,如果按enter鍵,得到的是’\r’,原因就在於enter鍵對應的字符是’\r’,而這兩個函數是直接獲得鍵盤輸入;

使用getchar()或scanf(“%c”, &ch)讀取字符,如果按enter鍵,得到的是’\n’,原因在於這兩個函數是從緩衝區獲取輸入,而按enter鍵的作用是將控制檯輸入寫入緩衝區,如下實例,鍵盤輸入a,回車後,a讀給了ch,'\n'讀給了ch2。

<code>	char ch,ch2;
	ch = getchar();
	cout


C|文本文件的文本、二進制存儲以及回車符和換行符的處理

-End-


分享到:


相關文章: