一、基本概念:
1、檔案流:
c 語言把檔案看作是乙個字元的序列,即檔案是由乙個乙個字元組成的字元流,因此 c 語言將檔案也稱之為檔案流。
即當讀寫乙個檔案時,可以不必關心檔案的格式或結構。
計算機檔案的儲存,物理上都是二進位制,所以文字檔案與二進位制檔案的區別並不是物理上的, 而是邏輯上的。這兩者只是在編碼層次上有差異。簡單來說,文字檔案是基於字元編碼的檔案,常見的編碼有 ascii 編碼,二進位制檔案是基於值編碼的檔案。
3、檔案緩衝:
檔案緩衝區(buffer) 存在的好處:首先,緩衝區在記憶體中,從記憶體中讀取資料比從檔案(硬碟)中讀取資料要快得多。
其次,對檔案的讀寫需要用到 fopen、fread、fwrite 等系統底層函式,而使用者程序每呼叫一次系統函式都要從使用者態切換到核心態,等執行完畢後再返回使用者態,這種切換要花費一定時間成本(對於高併發程式而言,這種狀態的切換會影響到程式效能)。
重新整理快取區:可以使用 fflush()。
二、檔案操作
1、檔案的開啟和關閉:
1)開啟fopen() 宣告 file * fopen ( const char * filename, const char * mode );
mode詳解:
2)關閉fclose() 宣告 int fclose ( file * stream );
成功返回0,失敗返回eof(-1)。
2、檔案的讀取和寫入(文字操作)
1)一次讀寫乙個字元
寫入 fputc() 宣告 int fputc (int ch, file * stream ); 寫入成功返回寫入的字元,失敗返回eof。
讀取 fgetc() 宣告 int fgetc ( file * stream ); 正常,返回讀取的字元;讀到檔案尾或出錯時,為 eof。
讀取字元,重點是判斷結束條件是什麼?通常的做法是依據返回值判斷。
2)一次讀寫一行字元
什麼是行:
行是文字編輯器中的概念,檔案流中就是乙個字元,不同的平台有差異。
換行符在window 平台是'\r\n',在linux 平台是'\n'。
平台差異:
①linux 讀 windows 中的換行,會多讀乙個字元,windows 讀 linux 中的換行,則沒有問題。
解決:dos2unix 命令
②linux 中無論使用 gedit 還是 vim ,系統都會自動在末行新增\n 標誌。windows 當中系統不會自動新增\n。
寫入 fputcs() 宣告 int fputs(char *str,file *fp); 正常,返 0;出錯返 eof。
讀取 fgetcs() 宣告 char *fgets(char *str,int length,file *fp);
正常,返 str 指標;出錯或遇到檔案結尾返空指標 null。
3、詳解 fgetcs() :
從 fp 所指向的檔案中,至多讀 length-1 個字元,送入字元陣列 str中, 如果在讀入 length-1 個字元結束前遇\n 或 eof,讀入即結束,字串讀入後在最後加乙個『\0』字元。
fgets 函式返回有三個條件:
1)讀 length-1 個字元前遇到\n,讀取結束(\n 被讀取) + \0。
2)讀 length-1 個字元前遇到 eof,讀取結束 +\0。
3)讀到length-1 個符 +\0。
4、檔案的讀寫(二進位制操作)----一次讀寫一塊資料
c 語言所有的檔案介面函式,要麼以 '\0',表示輸入結束,要麼以 '\n', eof(0xff)表示讀取結束,這些都是文字檔案的重要標識。而二進位制檔案,則往往以塊的形式,寫入或讀出。所有的二進位制介面對於這些標識,是不敏感的,把它們當做普通字元處理。
寫入 fwrite 宣告 int fwrite(void *buffer, int num_bytes, int count, file *fp);
讀取 fread 宣告int fread(void *buffer, int num_bytes, int count, file *fp);
返回值: 成功,返回讀/寫的字段數;出錯或檔案結束,返回 0。
注意 fread返回值陷阱:
#define _crt_secure_no_warnings
#include #include int main(void)
char *p = "123456789";
fwrite(p, 1, strlen(p), fpw);
rewind(fpw);
char buf[1024];
int n;
//錯誤讀法 4+4+0
n =fread((void*)buf,4,1,fpw);
printf("n = %d\n",n);
n =fread((void*)buf,4,1,fpw);
printf("n = %d\n",n);
n =fread((void*)buf,4,1,fpw); //按塊讀取,不夠4個導致出錯
printf("n = %d\n",n);
//正確讀法 4+4+1
/*n = fread((void*)buf, 1, 4, fpw);
printf("n = %d\n", n);
n = fread((void*)buf, 1, 4, fpw);
printf("n = %d\n", n);
n = fread((void*)buf, 1, 4, fpw);
printf("n = %d\n", n);*/
return 0;
}
分析:fread 依靠讀出塊的多少來標識讀結果和檔案結束標誌。因此讀取時最好以最小的單元格式進行讀,或是以寫入的最小單元進行讀。
5、檔案指標偏移函式:
1、rewind()宣告 void rewind ( file * stream ); 將檔案指標重新指向乙個流的開頭。
用途:如果乙個檔案具有讀寫屬性,則我們寫完檔案時,檔案指標指向結尾,當需要讀取時就需要 rewind函式。
2、ftell()宣告 long ftell ( file * stream );
成功,返回當前讀寫位置偏離檔案頭部的位元組數。失敗, 返回-1。
3、fseek()宣告 int fseek ( file * stream, long offset, int where); 偏移檔案指標
成功返回 0 ,失敗返回-1。
常見起始位置巨集定義:
#define seek_set 0 //檔案開頭
#define seek_cur 1 //當前位置
#define seek_end 2 //檔案結尾
/*簡單用法*/
fseek(fp,100l,0); //把 fp 指標移動到離檔案開頭 100 位元組處;
fseek(fp,100l,1); //把 fp 指標移動到離檔案當前位置 100 位元組處;
fseek(fp,-100l,2); //把 fp 指標退回到離檔案結尾 100 位元組處。
三、總結:前面簡單介紹了文字讀寫和二進位制讀寫,但歸根到底二進位制讀寫才是本質。
1、使用二進位制讀取功能更加強大,比如讀取結構體就非常適合,結構體包含各種型別,型別大小不一,使用二進位制就不需要考慮這些問題。
2、檔案讀寫特別注意如何判斷是否讀取成功,是否寫入完成,一般使用返回值判斷。
3、讀以下檔案,請問 fgets 共執行了多少次?
fgets( buf, 10, fp) ;
1234567890abcdefg(換行)
1234567890(換行)
abcdefg(eof)
分析:fgets 共執行了5次,length為10,所以每次最多讀10-1 = 9個字元。
第一次,讀到1~9 +\0 第二次,讀到0~g \n +\0 第三次,讀到1~9 +\0
第四次,讀到0 \n +\0 第五次,a~g +\0
c語言檔案讀寫操作
檔案讀取操作 file fp char fname d printf s n fname fp fopen fname,r fscanf fp,d buf printf d buf 0 fclose fp fread,與fwrite是binary stream input output二進位製流的輸...
C語言檔案讀寫操作
標頭檔案 include include include include 用於生成隨機數 建立檔案指標 file fp 檢測檔案是否開啟成功 if fp fopen f52.txt w null 如果檔案不存在,則會新建。w 即設定操作為 write 寫操作 隨機的產生,設定時間種子 srand t...
C語言檔案操作 開 關 讀 寫
概述 1.乙個c檔案是乙個位元組流或二進位製流,它把資料看作是一連串的字元 位元組 而不考慮記錄的界限。在c語言中對檔案的訪問是以字元 位元組 為單位的。注 流式檔案 輸出時不會自動增加回車換行符以作為記錄結束的標誌,輸入時不以回車換行符作為記錄的間隔 2.ansi c標準使用緩衝檔案系統處理文字檔...