C語言檔案讀寫操作總結

來源:互聯網
上載者:User

標籤:丟失   控制   term   type命令   分配   and   自己的   記錄   自己   

C語言檔案操作

一、標準檔案的讀寫

1.檔案的開啟

fopen() 檔案的開啟動作表示將給使用者指定的檔案在記憶體配置一個FILE結構區,並將該結構的指標返回給使用者程式,以後使用者程式就可用此FILE指標來實現對指定檔案的存取操作了。當使用開啟函數時,必須給出檔案名稱、檔案操作方式(讀、寫或讀寫),如果該檔案名稱不存在,就意味著建立(只對寫檔案而言,對讀檔案則出錯),並將檔案指標指向檔案開頭。若已有一個同名檔案存在,則刪除該檔案,若無同名檔案,則建立該檔案,並將檔案指標指向檔案開頭。

fopen(char *filename,char *type); 

其中*filename是要開啟檔案的檔案名稱指標,一般用雙引號括起來的檔案名稱表示,也可使用雙反斜線隔開的路徑名。而*type參數表示了對開啟檔案的操作方式。其可採用的操作方式如下: 方式 含義 "r" 開啟,唯讀; "w" 開啟,檔案指標指到頭,唯寫; "a" 開啟,指向檔案尾,在已存在檔案中追加; "rb" 開啟一個二進位檔案,唯讀; "wb" 開啟一個二進位檔案,唯寫; "ab" 開啟一個二進位檔案,進行追加 ;"r+" 以讀/寫方式開啟一個已存在的檔案; "w+" 以讀/寫方式建立一個新的文字檔 ;"a+" 以讀/寫方式開啟一個檔案檔案進行追加 ;"rb+" 以讀/寫方式開啟一個二進位檔案; "wb+" 以讀/寫方式建立一個新的二進位檔案 ;"ab+" 以讀/寫方式開啟一個二進位檔案進行追加 ;當用fopen()成功的開啟一個檔案時,該函數將返回一個FILE指標,如果檔案開啟失敗,將返回一個NULL指標。如想開啟test檔案,進行寫:

  1. FILE *fp;  
  2. if((fp=fopen("test","w"))==NULL) {  
  3.     printf("File cannot be opened/n");  
  4.     exit();  
  5. }  
  6. else  
  7.     printf("File opened for writing/n");  
  8. ……  
  9. fclose(fp);   

DOS作業系統對同時開啟的檔案數目是有限制的,預設值為5,可以通過修改CONFIG.SYS檔案改變這個設定。

2.關閉檔案函數fclose() 

檔案操作完成後,必須要用fclose()函數進行關閉,這是因為對開啟的檔案進行寫入時,若檔案緩衝區的空間未被寫入的內容填滿,這些內容不會寫到開啟的檔案中去而丟失。只有對開啟的檔案進行關閉操作時,停留在檔案緩衝區的內容才能寫到該檔案中去,從而使檔案完整。再者一旦關閉了檔案,該檔案對應的FILE結構將被釋放,從而使關閉的檔案得到保護,因為這時對該檔案的存取操作將不會進行。檔案的關閉也意味著釋放了該檔案的緩衝區。

int fclose(FILE *stream); 

它表示該函數將關閉FILE指標對應的檔案,並返回一個整數值。若成功地關閉了檔案,則返回一個0值,否則返回一個非0值。常用以下方法進行測試:

  1. if(fclose(fp)!=0) {  
  2.     printf("File cannot be closed/n");   
  3.     exit(1);   
  4. }   
  5. else  
  6.     printf("File is now closed/n");   

 

當開啟多個檔案進行操作,而又要同時關閉時,可採用fcloseall()函數,它將關閉所有在程式中開啟的檔案。 int fcloseall(); 該函數將關閉所有已開啟的檔案,將各檔案緩衝區未裝滿的內容寫到相應的檔案中去,接著釋放這些緩衝區,並返回關閉檔案的數目。如關閉了4個檔案,則當執行: n=fcloseall(); 時,n應為4。

3.檔案的讀寫

(1).讀寫檔案中字元的函數(一次唯讀寫檔案中的一個字元):

int fgetc(FILE *stream);

int getchar(void);

int fputc(int ch,FILE *stream);

int putchar(int ch); 

int getc(FILE *stream); 

int putc(int ch,FILE *stream); 

其中fgetc()函數將把由流指標指向的檔案中的一個字元讀出,例如: ch=fgetc(fp); 將把流指標fp指向的檔案中的一個字元讀出,並賦給ch,當執行fgetc()函數時,若當時檔案指標指到檔案尾,即遇到檔案結束標誌EOF(其對應值為-1),該函數返回一個-1給ch,在程式中常用檢查該函數傳回值是否為-1來判斷是否已讀到檔案尾,從而決定是否繼續。

  1. #include "stdio.h"   
  2. #include <stdlib.h>  
  3. int main() {   
  4.     FILE *fp;   
  5.     char ch;  
  6.     if((fp=fopen("myfile.txt","r"))==NULL) {  
  7.         printf("file cannot be opened/n");   
  8.         exit(1);   
  9.     }   
  10.     while((ch=fgetc(fp))!=EOF)   
  11.         fputc(ch,stdout);   
  12.     fclose(fp);   
  13. }   

該程式以唯讀方式開啟myfile.txt檔案,在執行while迴圈時,檔案指標每迴圈一次後移一個字元位置。用fgetc()函數將檔案指標指定的字元讀到ch變數中,然後用fputc()函數在螢幕上顯示,當讀到檔案結束標誌EOF時,關閉該檔案。 上面的程式用到了fputc()函數,該函數將字元變數ch的值寫到流指標指定的檔案中去,由於流指標用的是標準輸出(顯示器)的FILE指標stdout,故讀出的字元將在顯示器上顯示。又比如: fputc(ch,fp); 該函數執行結構,將把ch表示的字元送到流指標fp指向的檔案中去。 在TC中,putc()等價於fputc(),getc()等價於fgetc()。 putchar(c)相當於fputc(c,stdout);getchar()相當於fgetc(stdin)。 注意,這裡使用char ch,其實是不科學的,因為最後判斷結束標誌時,是看ch!=EOF,而EOF的值為-1,這顯然和char是不能比較的。所以,某些使用,我們都定義成int ch。

(2).讀寫檔案中字串的函數

char *fgets(char *string,int n,FILE *stream); 

char *gets(char *s); 

int fprintf(FILE *stream,char *format,variable-list); 

int fputs(char *string,FILE *stream);

int fscanf(FILE *stream,char *format,variable-list); 

其中fgets()函數將把由流指標指定的檔案中n-1個字元,讀到由指標string指向的字元數組中去,例如: fgets(buffer,9,fp); 將把fp指向的檔案中的8個字元讀到buffer記憶體區,buffer可以是定義的字元數組,也可以是動態分配的記憶體區。 注意,fgets()函數讀到‘/n‘就停止,而不管是否達到數目要求。同時在讀取字串的最後加上‘/0‘。 fgets()函數執行完以後,返回一個指向該串的指標。如果讀到檔案尾或出錯,則均返回一個null 指標NULL,所以長用feof()函數來測定是否到了檔案尾或者是ferror()函數來測試是否出錯,例如下面的程式用fgets()函數讀test.txt檔案中的第一行並顯示出來:

  1. #include "stdio.h"   
  2. int main() {  
  3.     FILE *fp;   
  4.     char str[128];   
  5.     if((fp=fopen("test.txt","r"))==NULL) {  
  6.         printf("cannot open file/n"); exit(1);  
  7.     }   
  8.     while(!feof(fp)) {  
  9.         if(fgets(str,128,fp)!=NULL)  
  10.         printf("%s",str);  
  11.     }  
  12.     fclose(fp);  
  13. }   

gets()函數執行時,只要未遇到分行符號或檔案結束標誌,將一直讀下去。因此讀到什麼時候為止,需要使用者進行控制,否則可能造成儲存區的溢出。 fputs()函數想指定檔案寫入一個由string指向的字串,‘/0‘不寫入檔案。 fprintf()和fscanf()同printf()和scanf()函數類似,不同之處就是printf()函數是想顯示器輸出,fprintf()則是向流指標指向的檔案輸出;fscanf()是從檔案輸入。 下面程式是向檔案test.dat裡輸入一些字元:

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. int main() {  
  4.     char *s="That‘s good news";   
  5.     int i=617;   
  6.     FILE *fp;  
  7.     fp=fopen("test.dat", "w"); /*建立一個文字檔案唯寫*/   
  8.     fputs("Your score of TOEFL is",fp); /*向所建檔案寫入一串字元*/   
  9.     fputc(‘:‘, fp); /*向所建檔案寫冒號:*/   
  10.     fprintf(fp, "%d/n", i); /*向所建檔案寫一整型數*/   
  11.     fprintf(fp, "%s", s); /*向所建檔案寫一字串*/   
  12.     fclose(fp);  
  13. }   

用DOS的TYPE命令顯示TEST.DAT的內容如下所示: 螢幕顯示 Your score of TOEFL is: 617 That‘s good news 下面的程式是把上面的檔案test.dat裡的內容在螢幕上顯示出來:

  1. #include <stdio.h>  
  2. int main() {  
  3.     char s[24], m[20];   
  4.     int i;  
  5.     FILE *fp;  
  6.     fp=fopen("test.dat", "r"); /*開啟文字檔案唯讀*/  
  7.     fgets(s, 24, fp); /*從檔案中讀取23個字元*/  
  8.     printf("%s", s);   
  9.     fscanf(fp, "%d", &i); /*讀取整型數*/  
  10.     printf("%d", i);   
  11.     putchar(fgetc(fp)); /*讀取一個字元同時輸出*/  
  12.     fgets(m, 17, fp); /*讀取16個字元*/   
  13.     puts(m); /*輸出所讀字串*/   
  14.     fclose(fp);   
  15. }   

運行後螢幕顯示: Your score of TOEFL is: 617 That‘s good news

4.清除和設定檔案緩衝區

(1).清除檔案緩衝區函數:

 int fflush(FILE *stream); 

int flushall();

 fflush()函數將清除由stream指向的檔案緩衝區裡的內容,常用於寫完一些資料後,立即用該函數清除緩衝區,以免誤操作時,破壞原來的資料。 flushall()將清除所有開啟檔案所對應的檔案緩衝區。

(2).設定檔案緩衝區函數

 void setbuf(FILE *stream,char *buf); 

void setvbuf(FILE *stream,char *buf,int type,unsigned size); 

這兩個函數將使得開啟檔案後,使用者可建立自己的檔案緩衝區,而不使用fopen()函數開啟檔案設定的預設緩衝區。 對於setbuf()函數,buf指出的緩衝區長度由標頭檔stdio.h中定義的宏BUFSIZE的值決定,預設值為512位元組。當選定buf為空白時,setbuf函數將使的檔案I/O不帶緩衝。而對setvbuf函數,則由malloc函數來分配緩衝區。參數size指明了緩衝區的長度(必須大於0),而參數type則表示了緩衝的類型,其值可以取如下值: type 值 含義 _IOFBF 檔案全部緩衝,即緩衝區裝滿後,才能對檔案讀寫 _IOLBF 檔案行緩衝,即緩衝區接收到一個分行符號時,才能對檔案讀寫 _IONBF 檔案不緩衝,此時忽略buf,size的值,直接讀寫檔案,不再經過檔案緩衝區緩衝。

5.檔案的隨機讀寫函數

 前面介紹的檔案的字元/字串讀寫,均是進行檔案的順序讀寫,即總是從檔案的開頭開始進行讀寫。這顯然不能滿足我們的要求,C語言提供了移動檔案指標和隨機讀寫的函數,它們是:

(1).移動檔案指標函數:

 long ftell(FILE *stream);

 int rewind(FILE *stream);

 fseek(FILE *stream,long offset,int origin);

 函數ftell()用來得到檔案指標離檔案開頭的位移量。當傳回值是-1時表示出錯。 rewind()函數用於檔案指標移到檔案的開頭,當移動成功時,返回0,否則返回一個非0值。 fseek()函數用於把檔案指標以origin為起點移動offset個位元組,其中origin指出的位置可有以下幾種:

 origin 數值 代表的具體位置 

SEEK_SET 0 檔案開頭

 SEEK_CUR 1 檔案指標當前位置

 SEEK_END 2 檔案尾 

例如: fseek(fp,10L,0); 把檔案指標從檔案開頭移到第10位元組處,由於offset參數要求是長整型數,故其數後帶L。

 fseek(fp,-15L,2); 把檔案指標從檔案尾向前移動15位元組。

(2).檔案隨機讀寫函數

 int fread(void *ptr,int size,int nitems,FILE *stream);

 int fwrite(void *ptr,int size,int nitems,FILE *stream);

 fread()函數從流指標指定的檔案中讀取nitems個資料項目,每個資料項目的長度為size個位元組,讀取的nitems資料項目存入由ptr指標指向的記憶體緩衝區中,在執行fread()函數時,檔案指標隨著讀取的位元組數而向後移動,最後移動結束的位置等於實際讀出的位元組數。該函數執行結束後,將返回實際讀出的資料項目數,這個資料項目數不一定等於設定的nitems,因為若檔案中沒有足夠的資料項目,或讀中間出錯,都會導致返回的資料項目數少於設定的nitems。當返回數不等於nitems時,可以用feof()或ferror()函數進行檢查。 fwrite()函數從ptr指向的緩衝區中取出長度為size位元組的nitems個資料項目,寫入到流指標stream指向的檔案中,執行該操作後,檔案指標將向後移動,移動的位元組數等於寫入檔案的位元組數目。該函數操作完成後,也將返回寫入的資料項目數。

二、非標準檔案的讀寫

 這類函數最早用於UNIX作業系統,ANSI標準未定義,但有時也經常用到,DOS 3.0以上版本支援這些函數。它們的標頭檔為io.h。 由於我們不常用這些函數,所以在這裡就簡單說一下。

1.檔案的開啟和關閉

 open()函數的作用是開啟檔案,其調用格式為: int open(char *filename, int access); 該函數表示按access的要求開啟名為filename的檔案,傳回值為檔案描述字,其中access有兩部分內容: 基本模式和修飾符, 兩者用" "("或")方式串連。修飾符可以有多個, 但基本模式只能有一個。 access的規定 -------------------------------------------------------- 基本模式 含義 修飾符 含 義 -------------------------------------------------------- O_RDONLY 唯讀 O_APPEND 檔案指標指向末尾 O_WRONLY 唯寫 O_CREAT 檔案不存在時建立檔案, 屬性按基本模式屬性 O_RDWR 讀寫 O_TRUNC 若檔案存在, 將其長度縮為0, 屬性不變 O_BINARY 開啟一個二進位檔案 O_TEXT 開啟一個文字檔案 --------------------------------------------------------- open()函數開啟成功, 傳回值就是檔案描述字的值(非負值), 否則返回-1。 close()函數的作用是關閉由open()函數開啟的檔案, 其調用格式為: int close(int handle); 該函數關閉檔案描述字handle相連的檔案。

2.讀寫函數

 int read(int handle, void *buf, int count);

 read()函數從handle(檔案描述字)相連的檔案中, 讀取count個位元組放到buf所指的緩衝區中, 傳回值為實際所讀位元組數, 返回-1表示出錯。返回0 表示檔案結束。 write()函數的調用格式為: int write(int handle, void *buf, int count); write()函數把count個位元組從buf指向的緩衝區寫入與handle相連的檔案中, 傳回值為實際寫入的位元組數。

3.隨機定位函數

 lseek()函數的調用格式為: int lseek(int handle, long offset, int fromwhere); 

該函數對與handle相連的檔案位置指標進行定位,功能和用法與fseek()函數相同。 tell()函數的調用格式為: long tell(int handle); 該函數返回與handle相連的檔案現生位置指標, 功能和用法與ftell()相同

5. read 函數和 write 函數

來源:螞蟻的 C/C++ 標準編程 antigloss

1. read 

#include ssize_t read(int filedes, void *buf, size_t nbytes); 傳回值:讀取到的位元組數;0(讀到 EOF);-1(出錯) read 函數從 filedes 指定的已開啟檔案中讀取 nbytes 位元組到 buf 中。以下幾種情況會導致讀取到的位元組數小於 nbytes :

A. 讀取普通檔案時,讀到檔案末尾還不夠 nbytes 位元組。例如:如果檔案只有 30 位元組,而我們想讀取 100 位元組,那麼實際讀到的只有 30 位元組,read 函數返回 30 。此時再使用 read 函數作用於這個檔案會導致 read 返回 0 。

B. 從終端裝置(terminal device)讀取時,一般情況下每次只能讀取一行。

C. 從網路讀取時,網路緩衝可能導致讀取的位元組數小於 nbytes 位元組。

D. 讀取 pipe 或者 FIFO 時,pipe 或 FIFO 裡的位元組數可能小於 nbytes 。

E. 從面向記錄(record-oriented)的裝置讀取時,某些面向記錄的裝置(如磁帶)每次最多隻能返回一個記錄。 F. 在讀取了部分資料時被訊號中斷。讀操作始於 cfo 。在成功返回之前,cfo 增加,增量為實際讀取到的位元組數。

2. write

 #include ssize_t write(int filedes, const void *buf, size_t nbytes); 傳回值:寫入檔案的位元組數(成功);-1(出錯)write 函數向 filedes 中寫入 nbytes 位元組資料,資料來源為 buf 。傳回值一般總是等於 nbytes,否則就是出錯了。常見的出錯原因是磁碟空間滿了或者超過了檔案大小限制。 對於普通檔案,寫操作始於 cfo 。如果開啟檔案時使用了 O_APPEND,則每次寫操作都將資料寫入檔案末尾。成功寫入後,cfo 增加,增量為實際寫入的位元組數。

C語言檔案讀寫操作總結

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.