|
發(fā)信人: LosComet (水母第3不厚道男), 信區(qū): CProgramming
標 題: binary和text方式打開文件的區(qū)別 發(fā)信站: 水木社區(qū) (Mon Apr 3 17:55:20 2006), 站內(nèi) 這里并不是要說文本文件和二進制文件有什么區(qū)別,這兩種文件之間的界限本來就很模糊 ,事實上,把所有文件當成二進制文件就可以了。在這個層次上,一個文件和一塊內(nèi)存沒 有什么區(qū)別,都是一個字節(jié)序列,一個字節(jié)就是一個介于0x00~0xFF之間的值 但是在Windows/DOS下,用fopen等函數(shù)打開文件的時候,最后一個參數(shù)里可以加上一個 "b"或者"t",用來告訴程序這個文件應(yīng)該用什么方式打開。關(guān)于他們的區(qū)別,在MSDN上是 這樣說的: t Open in text (translated) mode. In this mode, CTRL+Z is interpreted as an end-of-file character on input. In files opened for reading/writing with "a+", fopen checks for a CTRL+Z at the end of the file and removes it, if possible. This is done because using fseek and ftell to move within a file that ends with a CTRL+Z, may cause fseek to behave improperly near the end of the file. Also, in text mode, carriage return–linefeed combinations are translated into single linefeeds on input, and linefeed characters are translated to carriage return–linefeed combinations on output. When a Unicode stream-I/O function operates in text mode (the default), the source or destination stream is assumed to be a sequence of multibyte characters. Therefore, the Unicode stream-input functions convert multibyte characters to wide characters. For the same reason, the Unicode stream-output functions convert wide characters to multibyte characters. b Open in binary (untranslated) mode; translations involving carriage-return and linefeed characters are suppressed. If t or b is not given in mode, the default translation mode is defined by the global variable _fmode. If t or b is prefixed to the argument, the function fails and returns NULL. 為此,我做了如下的試驗: ====================================================================== #include <stdio.h> #include <stdlib.h> #include <string.h> void fwrite_test(){ FILE * ft; FILE * fb; int i; unsigned char b; // 用兩種模式打開兩個文件寫 ft = fopen("t.txt", "wt"); fb = fopen("b.txt", "wb"); // 將0x00-0xFF寫到兩個文件中 for(i = 0; i < 256; i++){ b = (unsigned char)i; fwrite(&b, 1, 1, ft); fwrite(&b, 1, 1, fb); } fclose(ft); fclose(fb); } void fread_test(const char * filename){ FILE * ft; FILE * fb; // 用來存儲從文件中讀出來的數(shù)據(jù) unsigned char buf_t[300] = {0}; unsigned char buf_b[300] = {0}; size_t cnt_t; size_t cnt_b; int i; // 用兩種方式打開同一個文件讀 ft = fopen(filename, "rt"); fb = fopen(filename, "rb"); // 把數(shù)據(jù)分別讀到buffer中,實際讀取的字節(jié)數(shù)放到變量中 cnt_t = fread(buf_t, 1, 300, ft); cnt_b = fread(buf_b, 1, 300, fb); // 輸出實際讀取的字節(jié)數(shù) printf("t mode read:%d\nb mode read:%d\n", cnt_t, cnt_b); // 輸出實際讀取的內(nèi)容 printf("\nbuffer t:\n"); for(i = 0; i < 300; i++){ printf("%X : 0x%X\n", i, buf_t[i]); } printf("\nbuffer b:\n"); for(i = 0; i < 300; i++){ printf("%X : 0x%X\n", i, buf_b[i]); } fclose(ft); fclose(fb); } int main (int argc, char **argv) { // 用兩種方式寫兩個文件 fwrite_test(); // 用兩種方式讀取binary方式寫入的文件 fread_test("b.txt"); printf("\n-------------------------------------\n"); // 分割線 // 用兩種方式讀取text方式寫入的文件 fread_test("t.txt"); }; ====================================================================== 編譯、運行上述代碼,生成test.exe,然后運行: test.exe > output.txt 這樣會生成3個文件,b.txt、t.txt、result.txt 首先察看文件大小,b.txt是256字節(jié)、t.txt是257字節(jié) 然后用16進制編輯器(我用的WinHex)打開兩個文件以對比 對比之后發(fā)現(xiàn),b.txt是從00-ff的256個字節(jié) 而t.txt中,在0x09和0x0A之間多了一個字節(jié),就是0x0D 然后看result.txt的內(nèi)容: 首先是,讀取那個用b方式生成的文件 用t方式打開的,只讀取了26個字節(jié) 而用b方式打開的,完整地讀取了256個字節(jié) 看看buffer中的內(nèi)容,buf_t中,只有前26個自節(jié)有值,后面都是0 也就是說,從第27個字節(jié)(0x1A)開始,后面的都沒有讀取 然后找到分割線,繼續(xù)看下面的內(nèi)容,讀取t.txt的內(nèi)容,也就是用t方式生成的多一個 0x0D的那個文件 這個文件共有257字節(jié),而用b方式打開之后也是讀取了257字節(jié) 但是看看t方式打開之后,仍然是讀取了26字節(jié) 看看buf_t里面的內(nèi)容,仍然是從0x00-0x19的這26個字節(jié) ====================================================================== 總結(jié): 0x0A是字符"\n"(換行,有時被稱為line feed、lf)、0x0D是字符"\r"(回車,carriage return)、0x1A是什么呢?我用VIM打開一個有0x1A的文件看到的是^Z 在t方式打開文件的時候,寫入一個0x0A,會被擴展為0x0D、0x0A,這個在以前的討論中 說過,也就是把\n轉(zhuǎn)化成\r\n,在t方式讀取的時候,0x0D、0x0A會被當作只有一個0x0A。 Ctrl-Z就是在Windows下的控制臺下輸入EOF是要按的鍵,也就是說,在讀取文件的時候 用t方式打開的話,會把0x1A當作是一個文件的結(jié)尾,也就是EOF,后面的內(nèi)容將不會視為 該文件的內(nèi)容。 而用b方式打開文件的時候,會原汁原味地交換內(nèi)存和文件中的數(shù)據(jù),沒有任何轉(zhuǎn)換。 在Windows下,如果不加b或者t,或者在C++里面不加ios::binary或ios::text 默認是按照t方式打開的文件(這個應(yīng)該所使用的庫有關(guān),反正VC是這樣的) 這一點要注意。 另外,我把剛才的程序拿到Linux下編譯運行了一次,結(jié)果是b和t沒有區(qū)別,表現(xiàn)出來的 行為和Windows下用b方式打開文件一樣,0x0A、0x1A等數(shù)據(jù)進行特別處理。 貼上Linux下的部分man page的內(nèi)容: man fopen: The mode string can also include the letter ``b'' either as a last character or as a character between the characters in any of the two- character strings described above. This is strictly for compatibility with ANSI X3.159-1989 (``ANSI C'') and has no effect; the ``b'' is ignored on all POSIX conforming systems, including Linux. (Other sys- tems may treat text files and binary files differently, and adding the ``b'' may be a good idea if you do I/O to a binary file and expect that your program may be ported to non-Unix environments.) 也就是說,Linux下b和t是沒有區(qū)別的 windows/dos真麻煩^_^ ——某斑竹語 |
|
|
來自: SpringEmpire > 《我的圖書館》