關於C之檔案結尾EOF與二進位制檔案換行符

2021-09-29 07:25:08 字數 3731 閱讀 1114

檔案結尾:

計算機作業系統要以某種方式判斷檔案的開始和結束。 檢測檔案結尾的一種方法是, 在檔案末尾放乙個特殊的字元標記檔案尾。

cp/m、 ibmdos和ms-dos的文字檔案曾經用過這種方法。 如今, 這些作業系統可以使用內嵌的ctrl+z字元來標記檔案結尾。 這曾經是作業系統使用的唯一標記,不過現在有一些其他的選擇, 例如記錄檔案的大小。 所以現代的文字檔案不一定有嵌入的ctrl+z, 但是如果有, 該作業系統會將其視為乙個檔案結尾標記。 

作業系統使用的另一種方法是儲存檔案大小的資訊。 如果檔案有3000位元組, 程式在讀到3000位元組時便達到檔案的末尾。 ms-dos 及其相關系統使用這種方法處理二進位制檔案, 因為用這種方法可以在檔案中儲存所有的字元,包括ctrl+z。 新版的dos也使用這種方法處理文字檔案。 unix使用這種方法處理所有的檔案。

無論作業系統實際使用何種方法檢測檔案結尾,在c語言中,用getchar()讀取檔案檢測到檔案結尾時將返回乙個特殊的值,即eof( end of file的縮寫)。scanf()函式檢測到檔案結尾時也返回eof。

通常, eof定義在stdio.**件中:#define eof (-1)

為什麼是-1?因為getchar()函式的返回值通常都介於0~127,這些值對應標準字符集。但是,如果系統能識別擴充套件字符集,該函式的返回值可能在0~255之間。無論哪種情況,-1都不對應任何字元,所以,該值可用於標記檔案結尾。

如果包含stdio.**件,並使用eof符號,就不必擔心eof值不同的問題。這裡關鍵要理解eof是乙個值,標誌著檢測到檔案結尾, 並不是在檔案中找得到的符號。

#include int main(void)
以上程式表示:重複輸入,直到檔案結尾。

輸入回車僅代表輸入了乙個換行符 !=eof,輸入-1也正常列印,所以輸入回車或eof對應的值都是結束不了程式的,因為-1也好eof也好,回車符也好,都僅僅只是輸入了相應的字元而已,並不是控制命令。對於mac os系統來說,輸入ctrl+d即傳送eof,這時getchar()==eof了,程式才結束終止。在pc中,要按下ctrl+z。

使用該程式進行鍵盤輸入, 要設法輸入eof字元。 不能只輸入字元eof, 也不能只輸入-1( 輸入-1會傳送兩個字元: 乙個連字元和乙個數字1) 。 正確的方法是, 必須找出當前系統的要求。 例如, 在大多數unix和linux系統中, 在一行開始處按下ctrl+d會傳輸檔案結尾訊號。 許多微型計算機系統都把一行開始處的ctrl+z識別為檔案結尾訊號, 一些系統把任意位置的ctrl+z解釋成檔案結尾訊號。

下面結出乙個開啟乙個檔案並顯示該檔案的例子:

#include #include // 為了使用exit()

int main()

while ((ch = getc(fp)) != eof) // getc(fp)從開啟的檔案中獲取乙個字元

putchar(ch);

fclose(fp); // 關閉檔案

return 0;

}

換行符:在文字處理中, cr, lf, crlf是不同作業系統上使用的換行符. 

windows/dos         :採用回車+換行(crlf)表示下一行. 

os x/unix/linux   :採用換行符lf表示下一行. 

mac os 9及以前    :採用回車符cr表示下一行. 

cr用符號'\r'表示, 十進位制ascii**是13, 十六進製制**為0x0d; 

lf用符號'\n'表示, 十進位制ascii**是10, 十六制為0x0a. 

所有windows平台上換行在文字檔案中是使用 0d 0a 兩個位元組表示, 而unix和os x平台上換行則是使用0a乙個位元組表示,在早期mac os 9平台上換行則是使用0d乙個位元組表示。 

一般作業系統上的執行庫會自動決定文字檔案的換行格式。如乙個程式在windows上執行就生成cr lf換行格式的文字檔案,而在os x/unix/linux上執行就生成lf格式換行的文字檔案。

在mac os系統下,輸入純檔案內容如下:

hello world

my doc!

然後用16進製制工具開啟此檔案:

通過ascii碼表我們可以確定16進製制的64對應字元'd',16進製制的21對應字元'!',16進製制的0a對應換行lf。並沒有檔案結尾符。

在windows系統下,用16進製制工具開啟同樣的檔案:

通過ascii碼表我們可以確定16進製制的0d 0a對應字元cr lf。其他與mac os系統相同。也並沒有檔案結尾符^z。就像上面所述,用儲存檔案大小的資訊來判斷結尾了,這樣可以儲存所有字元,當然包括^z了。

如果用16進製制開啟乙個.rtf、.docx這樣的同樣有著純檔案內容的檔案,得到的是很大一串的16進製製碼,並且好像找不到原來的文字內容了。乙個mydoc.docx檔案,同樣的內容文字,轉換結果一團亂麻(裡面含有格式、字型、字型大小、顏色、對齊方式等等大量描述的內容),如下:

在mac上執行如下**:(開啟乙個桌面上的內容為「abcdef"的文字text.rtf檔案,輸出所有字元)

scanf("%s", fname);

fp = fopen(fname, "r"); // open file for reading

while ((ch = getc(fp)) != eof) // gets a character from the open file

putchar(ch);

執行結果如下:

標誌換行

windows/dos

os x unix linux ...

\r\n ()

\n ()

假設有如下**:

/* 功能:逆序輸出檔案中的內容 */

char ch;

while(...)

從檔案指標file * fp所指向的檔案中依次讀取字元,這時就要判斷檔案結尾的問題,if語句內容可以如下:

//#define ctrl_z '\032'

if (ch != ctrl_z && ch != '\r')

putchar(ch);

ctrl+z對應於ascii中^z,對應字元為'\032'(八進位制)。詳見:關於ascii碼與轉義字元

在windows下最常見就是:在讀出時,將回車符'\r\n'解釋成'\n';在寫入時,將'\n'解釋成'\r\n'。

因為本例中getc()是從二進位制檔案以字元方式讀取的,不同作業系統它的換行符不一樣,由於是逆序輸出檔案中的內容,為了相容,先判斷最後乙個字元是否為結尾字元,如果是,因為是系統自動生成的,對內容無影響,不列印輸出。而對於windows系統,'\r\n'才代表換行,也是系統自動生成的,我們只需要換行的意義就行,所以過濾掉'\r'保留'\n',這樣對內容顯示也無任何影響。

關於二進位制檔案

二進位制檔案,這個再基礎不過的名詞,正因為它的無處不在,或許沒有人會關注它背後隱含的內容。其實我也一樣,在寫下這些文字之前,我也是認為二進位制檔案就像空氣一樣,平常得讓人完全忽略了。很偶然的,今天在寫 的時候使用了fopen函式 file fopen const char filename,cons...

C 之 讀寫二進位制檔案

binaryreader類用特定的編碼將基元資料型別讀作二進位制值。常用建構函式和常用函式 成員型別 成員名說明 建構函式 binaryreader stream 基於所提供的流,用 utf8encoding 初始化binaryreader 類的新例項。建構函式 binaryreader strea...

關於二進位制

二進位制是計算技術中廣泛採用的一種數制。二進位制數 據是用0和1兩個數碼來表示的數。它的基數為2,進製規則是 逢二進一 借位規則是 借一當二 由18世紀德國數理哲學大師萊布尼茲發現。當前的計算機 系統使用的基本上是二進位制系統。二進位制中的單位 1byte 位元組 8 bits 位 1kb 千位元組...