C語言文件讀寫操作總結


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文件,進行寫:

[cpp] view plaincopyprint?

  • FILE *fp;  
  • if((fp=fopen("test","w"))==NULL) {  
  •     printf("File cannot be opened/n");  
  •     exit();  
  • }  
  • else  
  •     printf("File opened for writing/n");  
  • ……  
  • fclose(fp);   

DOS操作系統對同時打開的文件數目是有限制的,缺省值為5,可以通過修改CONFIG.SYS文件改變這個設置。

2.關閉文件函數fclose()

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

int fclose(FILE *stream); 

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

[cpp] view plaincopyprint?

  • if(fclose(fp)!=0) {  
  •     printf("File cannot be closed/n");   
  •     exit(1);   
  • }   
  • else  
  •     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),該函數返回一個-1ch,在程序中常用檢查該函數返回值是否為-1來判斷是否已讀到文件尾,從而決定是否繼續。

[cpp] view plaincopyprint?

  • #include "stdio.h"   
  • #include <stdlib.h>  
  • int main() {   
  •     FILE *fp;   
  •     char ch;  
  •     if((fp=fopen("myfile.txt","r"))==NULL) {  
  •         printf("file cannot be opened/n");   
  •         exit(1);   
  •     }   
  •     while((ch=fgetc(fp))!=EOF)   
  •         fputc(ch,stdout);   
  •     fclose(fp);   
  • }   

該程序以只讀方式打開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,所以長用feof()函數來測定是否到了文件尾或者是ferror()函數來測試是否出錯,例如下面的程序用fgets()函數讀test.txt文件中的第一行並顯示出來:

[cpp] view plaincopyprint?

  • #include "stdio.h"   
  • int main() {  
  •     FILE *fp;   
  •     char str[128];   
  •     if((fp=fopen("test.txt","r"))==NULL) {  
  •         printf("cannot open file/n"); exit(1);  
  •     }   
  •     while(!feof(fp)) {  
  •         if(fgets(str,128,fp)!=NULL)  
  •         printf("%s",str);  
  •     }  
  •     fclose(fp);  
  • }   

gets()函數執行時,只要未遇到換行符或文件結束標志,將一直讀下去。因此讀到什么時候為止,需要用戶進行控制,否則可能造成存儲區的溢出。 fputs()函數想指定文件寫入一個由string指向的字符串,'/0'不寫入文件 fprintf()fscanf()printf()scanf()函數類似,不同之處就是printf()函數是想顯示器輸出,fprintf()則是向流指針指向的文件輸出;fscanf()是從文件輸入。 下面程序是向文件test.dat里輸入一些字符:

[cpp] view plaincopyprint?

  • #include <stdio.h>  
  • #include <stdlib.h>  
  • int main() {  
  •     char *s="That's good news";   
  •     int i=617;   
  •     FILE *fp;  
  •     fp=fopen("test.dat", "w"); /*建立一個文字文件只寫*/   
  •     fputs("Your score of TOEFL is",fp); /*向所建文件寫入一串字符*/   
  •     fputc(':', fp); /*向所建文件寫冒號:*/   
  •     fprintf(fp, "%d/n", i); /*向所建文件寫一整型數*/   
  •     fprintf(fp, "%s", s); /*向所建文件寫一字符串*/   
  •     fclose(fp);  
  • }   

DOSTYPE命令顯示TEST.DAT的內容如下所示: 屏幕顯示 Your score of TOEFL is: 617 That's good news 下面的程序是把上面的文件test.dat里的內容在屏幕上顯示出來:

[cpp] view plaincopyprint?

  • #include <stdio.h>  
  • int main() {  
  •     char s[24], m[20];   
  •     int i;  
  •     FILE *fp;  
  •     fp=fopen("test.dat", "r"); /*打開文字文件只讀*/  
  •     fgets(s, 24, fp); /*從文件中讀取23個字符*/  
  •     printf("%s", s);   
  •     fscanf(fp, "%d", &i); /*讀取整型數*/  
  •     printf("%d", i);   
  •     putchar(fgetc(fp)); /*讀取一個字符同時輸出*/  
  •     fgets(m, 17, fp); /*讀取16個字符*/   
  •     puts(m); /*輸出所讀字符串*/   
  •     fclose(fp);   
  • }   

運行后屏幕顯示: 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 增加,增量為實際寫入的字節數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM