標籤:style blog http color 使用 os io 檔案
C 語言檔案操作
1. 資料流:
程式與資料的互動以流的形式進行。fopen 即開啟資料流,fclose 即重新整理資料流。
所謂資料流,是一種抽象,表示這段資料像流一樣,需要逐步接收,不能隨機存取;也意味著是一段連續的內容,每塊資料之間的順序是確定的。比如一個很大的檔案,不能一次性載入到記憶體裡面,無法直接擷取檔案任意位置的內容,只能逐漸載入到記憶體。
比如 TCP 被抽象為 stream 而 UDP 被抽象為 block。
2. 緩衝區:
fopen 時, 磁碟 --> 緩衝區 ;
fread 時, 緩衝區 --> 程式 ;
fwrite 時,程式 --> 緩衝區 ;
fclose 時,緩衝區 --> 磁碟 ;
當進行檔案讀取時,不會直接對磁碟進行讀取,而是先開啟資料流,將磁碟上的檔案資訊拷貝到緩衝區內,然後程式再從緩衝區中讀取資料;
當進行檔案寫入時,不會直接對磁碟進行寫入,而是先寫入緩衝區,只有在“緩衝區已滿”或“關閉檔案”時,才會將資料寫入磁碟;
貌似可以設定不使用緩衝區,這種情況會使用低級 io 函數直接對磁碟進行操作,速度慢,不是標準函數,不好跨平台。
3. 文字模式和二進位模式:
fopen 時,可以指定開啟檔案的模式,"t" 表示文字模式,"b" 表示二進位模式;
使用文字模式開啟檔案的話,檔案中的 \r\n (斷行符號換行) 轉為 \n,儲存檔案到磁碟時,\n 會轉為 \r\n ;
為什麼會區分文字模式、二進位模式?
電腦還沒出現之前,使用打字機進行文本輸入,當寫完一行之後,需要進行兩個操作 斷行符號(return)、換行(next), 斷行符號是把列印頭移到行首,換行是把列印頭移到下一行。後來,電腦發明了,一些人認為換行需要兩個字元,太浪費,加一個就可以,這就出現了分歧。
Windows 按照打字機的形式,操作文字檔時,如果需要換行,要在字串結尾的地方輸入兩個字元 \r,\n;
Linux 沒這麼想,需要換行的時候,在字串結尾加一個字元 \n 就好了;
後來 ANSI 規定, C 語言中 \n 在文字模式下是“邏輯新行符”,讀寫時可根據平台和實體儲存體間進行轉換。
看到 ANSI 這樣的規定,Windows 考慮到要相容以前的文字檔,在實現 C 執行階段程式庫的時候,就在文本開啟和儲存的時候,對原先的 \r\n 進行了轉換;
而 Linux 的文字模式和二進位模式,沒有區別。
mac os 的文字模式 \r 代表新行……
VS2008 有時候會出現“行尾不一致,需要將行尾標準化嗎?”這樣的提示,並讓使用者選擇 Windows(CRLF),就是因為檔案的行尾代碼不是 \r\n 造成的,此時選擇確定或取消,只是把行尾代碼統一為 \r\n ,並不會出現什麼問題。
何時使用文字模式操作檔案?
我覺得只有在處理文字文件的時候需要使用文字模式,平時解析設定檔、組建記錄檔檔案等情境,使用二進位模式就好了。
注意:
文字檔只應該使用文字模式開啟;二進位檔案只應該使用二進位模式開啟;否則可能出現意外錯誤;
如果一個 文字檔 需要在 Windows 和 Linux 等系統間交替使用,那麼應該在操作檔案前對 分行符號 進行轉換;
4. 檔案指標:
大部分的讀取、寫入函數,都會移動檔案指標的位置。
主要函數:
fseek(); // 設定檔案指標位置
ftell(); // 擷取當前位置
rewind(); // 調整到最開始
宏:
SEEK_SET // 開始
SEEK_CUR // 當前位置
SEEK_END // 結尾
注意:
為了保持與過去不能同時進行讀寫操作的相容性,一個操作不能隨後直接緊跟一個輸出操作,反之亦然。如果要同時進行輸入和輸出操作,必須在其中插入fseek函數的調用。
當使用 r+,w+,a+ 等讀寫方式開啟檔案時,讀操作和寫操作之間必須有一個 fseek 來轉換讀寫狀態,否則可能出現不確定的情況:
fgets(buf, 6, pFile);
fseek(pFile, 0, 0); // 立即調用 fseek 將檔案指標調整到合適的位置
fputs("sosad", pFile);
5. EOF(End of File)
EOF是一個宏,很多函數會返回這個宏來表示檔案已經達到末尾或者函數執行過程中發生了錯誤。比如 fputs
feof(File*) 是一個函數,可以用來判斷檔案是否已經到達末尾;
6. C 語言檔案操作函數匯總:
開啟關閉: fopen,fclose,freopen(可以重新指定檔案模式)
讀寫:fgetc,fputc, fgets,fputs, fread,fwrite, fprintf,fscanf, getc,putc, getchar,putchar, gets,puts ...
緩衝區操作:fflush, setbuf,setbuffer, setlinebuf,setvbuf ...
7. 常用函數樣本:
void ReadBinaryFileToStr(const char* path, std::string& outStr){ FILE* pFile = fopen(path, "rb"); fseek(pFile, 0, SEEK_END); long lsize = ftell(pFile); rewind(pFile); char* pBuf = new char[lsize+1]; int ret = fread(pBuf, 1, lsize, pFile); if (ret == lsize) { pBuf[lsize] = ‘\0‘; outStr.append(pBuf); delete[] pBuf; } fclose(pFile);}void WriteBinaryFileFromStr(const char* path, std::string& inStr){ FILE* pFile = fopen(path, "wb"); fwrite(inStr.c_str(), sizeof(char), inStr.length(), pFile); fclose(pFile);}
參考文章:
http://blog.csdn.net/xiaodan007/article/details/8350193
http://blog.csdn.net/silyvin/article/details/7275037
http://xu020408.blog.163.com/blog/static/26548920094673814288/