C 文件

2018-05-20 17:16 更新

學(xué)習(xí)C - C文件

C程序員使用指針來(lái)管理用于讀取和寫入數(shù)據(jù)的流。

流只是文件或硬件設(shè)備,如顯示器或打印機(jī)。

要指向并管理C中的文件流,請(qǐng)使用名為FILE的數(shù)據(jù)結(jié)構(gòu)。

類型FILE的指針就像任何其他變量一樣創(chuàng)建。

#include <stdio.h> 
int main(void) { 
   //create 3 file pointers 
   FILE *pRead; 
   FILE *pWrite; 
   FILE *pAppend; 
   
   return 0;
} //end main 

上面的代碼創(chuàng)建了三個(gè)名為pRead,pWrite和pAppend的FILE指針變量。

每個(gè)FILE指針可以打開和管理單獨(dú)的數(shù)據(jù)文件。



打開和關(guān)閉文件

文件處理的基本組件是打開,處理和關(guān)閉數(shù)據(jù)文件。

打開一個(gè)文件應(yīng)該有錯(cuò)誤檢查和/或處理。

未能測(cè)試文件打開的結(jié)果將導(dǎo)致不必要的程序結(jié)果。

要打開數(shù)據(jù)文件,請(qǐng)使用標(biāo)準(zhǔn)輸入/輸出庫(kù)函數(shù)fopen()。

fopen()函數(shù)返回一個(gè)指向FILE指針的FILE指針。


#include <stdio.h> 
main() 
{ 
   FILE *pRead; 
   pRead = fopen("file1.dat", "r"); 
} //end main  

該程序使用fopen()函數(shù)以只讀方式打開名為file1.dat的數(shù)據(jù)文件。

fopen()函數(shù)返回一個(gè)FILE指針?lè)祷氐絧Read變量。

fopen()函數(shù)有兩個(gè)參數(shù):文件名,第二個(gè)參數(shù)告訴fopen()如何打開文件。

下表列出了使用fopen()打開文本文件的幾個(gè)常用選項(xiàng)。

模式描述
r打開文件進(jìn)行閱讀
w創(chuàng)建寫入文件; 丟棄任何以前的數(shù)據(jù)
a寫入文件結(jié)尾(追加)

上面的代碼生成以下結(jié)果。



打開文件示例

打開文件后,應(yīng)確保文件指針成功返回。

要測(cè)試fopen()的返回值,請(qǐng)測(cè)試條件中的NULL值,如下所示。


#include <stdio.h> 
main() 
{ 
   FILE *pRead; 
   pRead = fopen("file1.dat", "r"); 
   if ( pRead == NULL ) 
      printf("\nFile cannot be opened\n"); 
   else 
      printf("\nFile opened for reading\n"); 
} //end main 

以下條件

if ( pRead == NULL )

可以縮短下一個(gè)條件。

if ( pRead ) 

如果pRead返回非NULL,則if條件為true。如果pRead返回NULL,則該條件為false。

成功打開和處理文件后,應(yīng)使用函數(shù)fclose()關(guān)閉文件。

fclose()函數(shù)使用FILE指針來(lái)刷新流并關(guān)閉文件。

fclose()函數(shù)將FILE指針名稱作為參數(shù)。

fclose(pRead);

上面的代碼生成以下結(jié)果。

讀取數(shù)據(jù)

以下代碼顯示如何使用函數(shù)fscanf()和feof()讀取文件的內(nèi)容并檢查文件的EOF(文件結(jié)尾)標(biāo)記。

以下程序讀取名為.dat的數(shù)據(jù)文件,直到讀取文件結(jié)束標(biāo)記為止。


#include <stdio.h> 
main() 
{ 
   FILE *pRead; 
   char name[10]; 
   pRead = fopen("names.dat", "r"); 
   if ( pRead == NULL ) 
      printf("\nFile cannot be opened\n"); 
   else 
      printf("\nContents of names.dat\n\n"); 
   fscanf(pRead, "%s", name); 
   while ( !feof(pRead) ) { 
         printf("%s\n", name); 
         fscanf(pRead, "%s", name); 
   }  //end loop 
} //end main 

在成功打開names.dat之后,我使用fscanf()函數(shù)來(lái)讀取文件中的一個(gè)字段。

fscanf()函數(shù)與scanf()函數(shù)類似,但與FILE流有關(guān)。

它有三個(gè)參數(shù):一個(gè)FILE指針,一個(gè)數(shù)據(jù)類型和一個(gè)變量來(lái)存儲(chǔ)檢索到的值。

讀取記錄后,printf()函數(shù)顯示文件中的數(shù)據(jù)。

要讀取多個(gè)記錄,請(qǐng)使用可以讀取所有記錄的循環(huán),直到滿足條件。

要讀取所有記錄,直到滿足文件結(jié)尾,請(qǐng)使用feof()函數(shù)。

使用非運(yùn)算符(!),可以將FILE指針傳遞給feof()函數(shù)并循環(huán),直到達(dá)到文件結(jié)尾標(biāo)記時(shí)函數(shù)返回非零值。

通過(guò)向第二個(gè)參數(shù)提供記錄中每個(gè)字段的一系列類型說(shuō)明符,fscanf()也可以讀取包含多個(gè)字段的記錄。

例如,下一個(gè)fscanf()函數(shù)希望讀取兩個(gè)名為name和hobby的字符串。

fscanf(pRead, "%s%s", name, hobby);

%s類型說(shuō)明符將讀取一系列字符,直到找到空白,包括空白,新行或選項(xiàng)卡。

fscanf()函數(shù)的其他有效類型說(shuō)明符列在表11.3中。

類型描述
c單字符
d十進(jìn)制整數(shù)
e,E,f,g,G浮點(diǎn)
o八進(jìn)制整數(shù)
s字符串
u無(wú)符號(hào)十進(jìn)制整數(shù)
x,X十六進(jìn)制整數(shù)

上面的代碼生成以下結(jié)果。

多個(gè)字段示例

以下代碼顯示如何讀取多個(gè)字段。


#include <stdio.h> 
main() 
{ 
   FILE *pRead; 
   char name[10]; 
   char hobby[15]; 
   pRead = fopen("hobbies.dat", "r"); 
   if ( pRead == NULL ) 
      printf("\nFile cannot be opened\n"); 
   else 
      printf("\nName\tHobby\n\n"); 

   fscanf(pRead, "%s%s", name, hobby); 
   while ( !feof(pRead) ) { 
         printf("%s\t%s\n", name, hobby); 
         fscanf(pRead, "%s%s", name, hobby); 
   }  //end loop 
} //end main 

上面的代碼生成以下結(jié)果。

寫數(shù)據(jù)

fprintf()函數(shù)接收FILE指針,數(shù)據(jù)類型列表以及將數(shù)據(jù)寫入數(shù)據(jù)文件的值列表。

例子

通過(guò)用記錄分隔記錄中的每個(gè)字段,我可以使用以下程序輕松地讀取相同的記錄。


#include <stdio.h> 
main() 
{ 
   FILE *pRead; 
   char fName[20]; 
   char lName[20]; 
   char id[15]; 
   float gpa; 
   pRead = fopen("students.dat", "r"); 
   if ( pRead == NULL ) 
      printf("\nFile not opened\n"); 
   else { 
      //print heading 
      printf("\nName\t\tID\t\tGPA\n\n"); 
      //read field information from data file and store in variables 
      fscanf(pRead, "%s%s%s%f", fName, lName, id, &gpa); 
      //print variable data to standard output 
      printf("%s %s\t%s\t%.2f\n", fName, lName, id, gpa); 
      fclose(pRead); 
   }  //end if 
} //end main  

使用帶有w參數(shù)值的fopen()打開數(shù)據(jù)文件將會(huì)擦除文件中存儲(chǔ)的任何以前的數(shù)據(jù)。

使用a屬性在文件末尾附加數(shù)據(jù)。

上面的代碼生成以下結(jié)果。

附加數(shù)據(jù)

將信息附加到數(shù)據(jù)文件中,包括使用fopen()中的一個(gè)屬性打開一個(gè)寫入文件,并將數(shù)據(jù)寫入現(xiàn)有文件的末尾。

但是,如果該文件不存在,則會(huì)按照f(shuō)open()語(yǔ)句中的指定創(chuàng)建一個(gè)新的數(shù)據(jù)文件。

以下代碼演示將記錄附加到現(xiàn)有數(shù)據(jù)文件。

#include <stdio.h> 
void readData(void); 
main() 
{ 
   FILE *pWrite; 
   char name[10]; 
   char hobby[15]; 
   printf("\nCurrent file contents:\n"); 
   readData(); 
   printf("\nEnter a new name and hobby: "); 
   scanf("%s%s", name, hobby); 
   //open data file for append 
   pWrite = fopen("hobbies.dat", "a"); 
   if ( pWrite == NULL ) 
      printf("\nFile cannot be opened\n"); 
   else { 
      //append record information to data file 
      fprintf(pWrite, "%s %s\n", name, hobby); 
      fclose(pWrite); 
      readData(); 
   }  //end if 
} //end main 

void readData(void) 
{ 
   FILE *pRead; 
   char name[10]; 
   char hobby[15]; 
   //open data file for read access only 
   pRead = fopen("hobbies.dat", "r"); 
   if ( pRead == NULL ) 
      printf("\nFile cannot be opened\n"); 
   else { 
      printf("\nName\tHobby\n\n"); 
      fscanf(pRead, "%s%s", name, hobby); 
      //read records from data file until end of file is reached 
      while ( !feof(pRead) ) { 
         printf("%s\t%s\n", name, hobby); 
         fscanf(pRead, "%s%s", name, hobby); 
      } 
   }
   fclose(pRead); 
} //end readData 

上面的代碼生成以下結(jié)果。

例2

以下代碼使用goto和一些新功能(perror()和exit())來(lái)構(gòu)建文件I/O程序中的錯(cuò)誤處理。


#include <stdio.h> 
#include <stdlib.h> 
main() { 
   FILE *pRead; 
   char name[10]; 
   char hobby[15]; 
   pRead = fopen("hobbies.dat", "r"); 
   if ( pRead == NULL ) 
      goto ErrorHandler; 
   else { 
      printf("\nName\tHobby\n\n"); 
      fscanf(pRead, "%s%s", name, hobby); 
      while ( !feof(pRead) ) { 
         printf("%s\t%s\n", name, hobby); 
         fscanf(pRead, "%s%s", name, hobby); 
      }  //end loop 
   } // end if 
   exit(EXIT_SUCCESS); //exit program normally 
   ErrorHandler: 
        perror("The following error occurred"); 
        exit(EXIT_FAILURE); //exit program with error 

} //end main 

exit()函數(shù)(<stdlib.h>庫(kù)的一部分)終止程序,就好像它正常退出一樣。

如下所示,exit()函數(shù)對(duì)于想要在遇到文件I/O(輸入/輸出)錯(cuò)誤時(shí)終止程序的程序員很常見。

exit(EXIT_SUCCESS); //exit program normally


exit(EXIT_FAILURE); //exit program with error 

exit()函數(shù)接受一個(gè)參數(shù),一個(gè)常量為EXIT_SUCCESS或EXIT_FAILURE,兩者都分別為成功或失敗返回預(yù)定義的值。

perror()函數(shù)向標(biāo)準(zhǔn)輸出發(fā)送消息,描述遇到的最后一個(gè)錯(cuò)誤。

perror()函數(shù)采用單個(gè)字符串參數(shù),首先打印,后跟冒號(hào)和空白,然后系統(tǒng)生成錯(cuò)誤消息和新行。

perror("The following error occurred");

上面的代碼生成以下結(jié)果。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)