C語言文件操作

13.3 文件的打開與關閉文件在進行讀寫操作之前要先打開,使用完畢要關閉。所謂打開文件,實際上是建立文件的各種有關信息,並使文件指針指向該文件,以便進行其它操作。關閉文件則斷開指針與文件之間的聯繫,也就禁止再對該文件進行操作。

  在C語言中,文件操作都是由庫函數來完成的。在本章內將介紹主要的文件操作函數。

  13.3.1 文件的打開(fopen函數)

  fopen函數用來打開一個文件,其調用的一般形式爲:

  文件指針名=fopen(文件名,使用文件方式);

  其中,

  “文件指針名”必須是被說明爲FILE 類型的指針變量:“文件名”是被打開文件的文件名:“使用文件方式”是指文件的類型和操作要求。

  “文件名”是字符串常量或字符串數組。

  例如:

  FILE *fp;fp=("file a","r");

  其意義是在當前目錄下打開文件file a,只允許進行“讀”操作,並使fp指向該文件。

  又如:

  FILE *fphzk fphzk=("c:\\hzk16","rb")

  其意義是打開C驅動器磁盤的根目錄下的文件hzk16,這是一個二進制文件,只允許按二進制方式進行讀操作。兩個反斜線“\\ ”中的第一個表示轉義字符,第二個表示根目錄。

  使用文件的方式共有12種,下面給出了它們的符號和意義。

  文件使用方式意義

  “rt”

  只讀打開一個文本文件,只允許讀數據

  “wt”

  只寫打開或建立一個文本文件,只允許寫數據

  “at”

  追加打開一個文本文件,並在文件末尾寫數據

  “rb”

  只讀打開一個二進制文件,只允許讀數據

  “wb”

  只寫打開或建立一個二進制文件,只允許寫數據

  “ab”

  追加打開一個二進制文件,並在文件末尾寫數據

  “rt+”

  讀寫打開一個文本文件,允許讀和寫

  “wt+”

  讀寫打開或建立一個文本文件,允許讀寫

  “at+”

  讀寫打開一個文本文件,允許讀,或在文件末追加數據

  “rb+”

  讀寫打開一個二進制文件,允許讀和寫

  “wb+”

  讀寫打開或建立一個二進制文件,允許讀和寫

  “ab+”

  讀寫打開一個二進制文件,允許讀,或在文件末追加數據

  對於文件使用方式有以下幾點說明:

  1) 文件使用方式由r,w,a,t,b,+六個字符拼成,各字符的含義是:

  r(read): 讀

  w(write): 寫

  a(append): 追加

  t(text): 文本文件,可省略不寫

  b(banary): 二進制文件

  +: 讀和寫

  2) 凡用“r”打開一個文件時,該文件必須已經存在,且只能從該文件讀出。

  3) 用“w”打開的文件只能向該文件寫入。若打開的文件不存在,則以指定的文件名建立該文件,若打開的文件已經存在,則將該文件刪去,重建一個新文件。

  4) 若要向一個已存在的文件追加新的信息,只能用“a”方式打開文件。但此時該文件必須是存在的,否則將會出錯。

  5) 在打開一個文件時,如果出錯,fopen將返回一個空指針值NULL.在程序中可以用這一信息來判別是否完成打開文件的工作,並作相應的處理。因此常用以下程序段打開文件:

  6) if((fp=fopen("c:\\hzk16","rb")==NULL)

  {

  printf("\nerror on open c:\\hzk16 file!");

  getch();

  exit(1);

  }

  這段程序的意義是,如果返回的指針爲空,表示不能打開C盤根目錄下的hzk16文件,則給出提示信息“error on open c:\ hzk16 file!”,下一行getch()的功能是從鍵盤輸入一個字符,但不在屏幕上顯示。在這裏,該行的作用是等待,只有當用戶從鍵盤敲任一lose函數返回值爲0.如返回非零值則表示有錯誤發生。

  13.4 文件的讀寫對文件的讀和寫是最常用的文件操作。在C語言中提供了多種文件讀寫的函數:

  。字符讀寫函數 :fgetc和fputc.字符串讀寫函數:fgets和fputs.數據塊讀寫函數:fread和fwrite.格式化讀寫函數:fscanf和fprinf

  下面分別予以介紹。使用以上函數都要求包含頭文件stdio.h.

  13.4.1 字符讀寫函數fgetc和fputc字符讀寫函數是以字符(字節)爲單位的讀寫函數。每次可從文件讀出或向文件寫入一個字符。

  1. 讀字符函數fgetc fgetc函數的功能是從指定的文件中讀一個字符,函數調用的形式爲:字符變量=fgetc(文件指針);

  例如:

  ch=fgetc(fp);

  其意義是從打開的文件fp中讀取一個字符並送入ch中。

  對於fgetc函數的使用有以下幾點說明:1) 在fgetc函數調用中,讀取的文件必須是以讀或讀寫方式打開的。

  2) 讀取字符的結果也可以不向字符變量賦值,

  例如:fgetc(fp);但是讀出的字符不能保存。

  3) 在文件內部有一個位置指針。用來指向文件的當前讀寫字節。在文件打開時,該指針總是指向文件的第一個字節。使用fgetc 函數後,該位置指針將向後移動一個字節。 因此可連續多次使用fgetc函數,讀取多個字符。應注意文件指針和文件內部的位置指針不是一回事。文件指針是指向整個文件的,須在程序中定義說明,只要不重新賦值,文件指針的值是不變的。文件內部的位置指針用以指示文件內部的當前讀寫位置,每讀寫一次,該指針均向後移動,它不需在程序中定義說明,而是由系統自動設置的。 (#add fgets也一樣)

  「例13.1」讀入文件c1.doc,在屏幕上輸出。

  #include<stdio.h> main()

  { FILE *fp;char ch;if((fp=fopen("d:\\jrzh\\example\\c1.txt","rt"))==NULL)

  { printf("\nCannot open file strike any key exit!");getch();exit(1);} ch=fgetc(fp);while(ch!=EOF)

  { putchar(ch);ch=fgetc(fp);} fclose(fp);}

  本例程序的功能是從文件中逐個讀取字符,在屏幕上顯示。程序定義了文件指針fp,以讀文本文件方式打開文件“d:\\jrzh\\example\\ex1_1.c”,並使fp指向該文件。如打開文件出錯,給出提示並退出程序。程序第12行先讀出一個字符,然後進入循環,只要讀出的字符不是文件結束標誌(每上,再讀入下一字符。每讀一次,文件內部的位置指針向後??本程序將顯示整個文件。

  2. 寫字符函數fputc

  fputc函數的功能??爲:

  fputc(字符量,文件指量或變量,例如:

  fputc('a',fp);

  其意putc函數的使用也要說明幾點:

  1) 被寫入的文件可以用寫、讀寫、追加方式打開,用寫或讀寫方式??寫入字符從文件首開始。如需保留原有文件內容,希望寫入的字??被寫入的文件若不存在,則創建該文件。

  2) 每寫入一個字符,文件內部位置指針向後移動一個字節。

  3) fputc函數有一個返回值,如寫入成功則返回寫入的字符,否則返回一個EOF.可用此來判斷寫符,寫入一個文件,再把該文件內容讀出顯示在屏幕上。

  #include<stdio.h>

  main()

  {

  FILE *fp;

  char ch;

  if((fp=fopen("d:\\jrzh\\example\\string","wt+"))==NULL)

  {

  printf("Cannot open file strike any key exit!");

  getch();

  exit(1);

  }

  printf("input a string:\n");

  ch=getchar();

  while (ch!='\n')

  {

  fputc(ch,fp);

  ch=getchar();

  }

  rewind(fp);

  ch=fgetc(fp);

  while(ch!=EOF)

  {

  putchar(ch);

  ch=fgetc(fp);

  }

  printf("\n");

  fclose(fp);

  }

  程序中第6行以讀寫文本文件方式打開文件string.程序第13行從鍵盤讀入一個字符後進入循環,當讀入字符不爲回車符時,則把該字符寫入文件之中,然後繼續從鍵盤讀入下一字符。每輸入一個字符,文件內部位置指針向後移動一個字節。寫入完畢,該指針已指向文件末。如要把文件從頭讀出,須把指針移向文件頭,程序第19行rewind函數用於把fp所指文件的內部位置指針移到文件頭。第20至25行用於讀出文件中的一行內容。

  「例13.3」把命令行參數中的前一個文件名標識的文件,複製到後一個文件名標識的文件中,如命令行中只有一個文件名則把該文件寫到標準輸出文件(顯示器)中。

  #include<stdio.h>

  main(int argc,char *argv[])

  {

  FILE *fp1,*fp2;

  char ch;

  if(argc==1)

  {

  printf("have not enter file name strike any key exit");

  getch();

  exit(0);

  }

  if((fp1=fopen(argv[1],"rt"))==NULL)

  {

  printf("Cannot open %s\n",argv[1]);

  }

  在ANSI C中,對文件的操作分爲兩種方式,即流式文件操作和I/O文件操作,下面就分別介紹之。

  一、流式文件操作這種方式的文件操作有一個重要的結構FILE,FILE在stdio.h中定義如下:typedef struct { int level; /* fill/empty level of buffer */ unsigned flags; /* File status flags */ char fd; /* File descriptor */ unsigned char hold; /* Ungetc char if no buffer */ int bsize; /* Buffer size */ unsigned char _FAR *buffer; /* Data transfer buffer */ unsigned char _FAR *curp; /* Current active pointer */ unsigned istemp; /* Temporary file indicator */ short token; /* Used for validity checking */ } FILE; /* This is the FILE object */ FILE這個結構包含了文件操作的基本屬性,對文件的操作都要通過這個結構的指針來進行,此種文件操作常用的函數見下表 函數 功能fopen() 打開流fclose() 關閉流fputc() 寫一個字符到流中fgetc() 從流中讀一個字符fseek() 在流中定位到指定的字符fputs() 寫字符串到流fgets() 從流中讀一行或指定個字符fprintf() 按格式輸出到流fscanf() 從流中按格式讀取feof() 到達文件尾時返回真值ferror() 發生錯誤時返回其值rewind() 復位文件定位器到文件開始處remove() 刪除文件fread() 從流中讀指定個數的字符fwrite() 向流中寫指定個數的字符tmpfile() 生成一個臨時文件流tmpnam() 生成一個唯一的文件名下面就介紹一下這些函數1.fopen()

  fopen的原型是:FILE *fopen(const char *filename,const char *mode),fopen實現三個功能爲使用而打開一個流 ;把一個文件和此流相連接;給此流返回一個FILR指針參數filename指向要打開的文件名,mode表示打開狀態的字符串,其取值如下表"r" 以只讀方式打開文件                   "w" 以只寫方式打開文件               "a" 以追加方式打開文件"r+" 以讀/寫方式打開文件,如無文件出錯             "w+" 以讀/寫方式打開文件,如無文件生成新文件一個文件可以以文本模式或二進制模式打開,這兩種的區別是:在文本模式中回車被當成一個字符'n',而二進制模式認爲它是兩個字符0x0D,0x0A;如果在文件中讀到0x1B,文本模式會認爲這是文件結束符,也就是二進制模型不會對文件進行處理,而文本方式會按一定的方式對數據作相應的轉換。

  系統默認的是以文本模式打開,可以修改全部變量_fmode的值來修改這個設置,例如_fmode=O_TEXT;就設置默認打開方式爲文本模式;而_fmode=O_BINARY;則設置默認打開方式是二進制模式。

  我們也可以在模式字符串中指定打開的模式,如"rb"表示以二進制模式打開只讀文件,"w+t"或"wt+"表示以文本模式打開讀/寫文件。

  此函數返回一個FILE指針,所以申明一個FILE指針後不用初始化,而是用fopen()來返回一個指針並與一個特定的文件相連,如果成敗,返回NULL.例:  FILE *fp;if(fp=fopen("123.456","wb"))

  puts("打開文件成功");else puts("打開文件成敗");2.fclose() 的功能就是關閉用fopen()打開的文件,其原型是:int fclose(FILE *fp);如果成功,返回0,失敗返回EOF.在程序結束時一定要記得關閉打開的文件,不然可能會造成數據丟失的情況,我以前就經常犯這樣的毛病。

  3.fputc()向流寫一個字符,原型是int fputc(int c, FILE *stream); 成功返回這個字符,失敗返回EOF.例:fputc('X',fp);4.fgetc()從流中讀一個字符,原型是int fputc(FILE *stream); 成功返回這個字符,失敗返回EOF.例:char ch1=fgetc(fp);5. fseek()此函數一般用於二進制模式打開的文件中,功能是定位到流中指定的位置,原型是int fseek(FILE *stream, long offset, int whence);如果成功返回0,參數offset是移動的字符數,whence是移動的基準,取值是符號常量 值 基準位置SEEK_SET 0 文件開頭SEEK_CUR 1 當前讀寫的位置SEEK_END 2 文件尾部例:fseek(fp,1234L,SEEK_CUR);//把讀寫位置從當前位置向後移動1234字節(L後綴表示長整數)

  fseek(fp,0L,2);//把讀寫位置移動到文件尾6.fputs() 寫一個字符串到流中,原型int fputs(const char *s, FILE *stream);例:fputs("I Love You",fp);7.fgets()從流中讀一行或指定個字符,原型是char *fgets(char *s, int n, FILE *stream); 從流中讀取n-1個字符,除非讀完一行,參數s是來接收字符串,如果成功則返回s的指針,否則返回NULL.例:如果一個文件的當前位置的文本如下Love ,I Have But ……

  如果用 fgets(str1,4,file1);  則執行後str1="Lov",讀取了4-1=3個字符,而如果用fgets(str1,23,file1);則執行str="Love ,I Have",讀取了一行(不包括行尾的'n')。

  8.fprintf()按格式輸入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, ……]);其用法和printf()相同,不過不是寫到控制檯,而是寫到流罷了。例:fprintf(fp,"%2d%s",4,"Hahaha");9.fscanf() 從流中按格式讀取,其原型是int fscanf(FILE *stream, const char *format[, address, ……]);其用法和scanf()相同,不過不是從控制檯讀取,而是從流讀取罷了。例:fscanf(fp,"%d%d" ,&x,&y);10.feof() 檢測是否已到文件尾,是返回真,否則返回0,其原型是int feof(FILE *stream);例:if(feof(fp))printf("已到文件尾");11.ferror() 原型是int ferror(FILE *stream);返回流最近的錯誤代碼,可用clearerr()來清除它,clearerr()的原型是void clearerr(FILE *stream); 例:printf("%d",ferror(fp));12.rewind()把當前的讀寫位置回到文件開始,原型是void rewind(FILE *stream);其實本函數相當於fseek(fp,0L,SEEK_SET);例:rewind(fp);12.remove() 刪除文件,原型是int remove(const char *filename); 參數就是要刪除的文件名,成功返回0.例:remove("c:io.sys");13.fread()  從流中讀指定個數的字符,原型是size_t fread(void *ptr, size_t size, size_t n, FILE *stream);參數ptr是保存讀取的數據,void*的指針可用任何類型的指針來替換,如char*、int *等等來替換;size是每塊的字節數;n是讀取的塊數,如果成功,返回實際讀取的塊數(不是字節數),本函數一般用於二進制模式打開的文件中。

  例:char x[4230];FILE *file1=fopen("c:msdos.sys","r");fread(x,200,12 ,file1);//共讀取200*12=2400個字節14.fwrite() 與fread對應,向流中寫指定的數據,原型是size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);參數ptr是要寫入的數據指針,void*的指針可用任何類型的指針來替換,如char*、int *等等來替換;size是每塊的字節數;n是要寫的塊數,如果成功,返回實際寫入的塊數(不是字節數),本函數一般用於二進制模式打開的文件中。

  例:char x[]="I Love You";fwire(x, 6,12,fp);//寫入6*12=72字節將把"I Love"寫到流fp中12次,共72字節15.tmpfile() 其原型是FILE *tmpfile(void); 生成一個臨時文件,以"w+b"的模式打開,並返回這個臨時流的指針,如果失敗返回NULL.在程序結束時,這個文件會被自動刪除。例:FILE *fp=tmpfile();16.tmpnam();其原型爲char *tmpnam(char *s); 生成一個唯一的文件名,其實tmpfile()就調用了此函數,參數s用來保存得到的文件名,並返回這個指針,如果失敗,返回NULL.例:tmpnam(str1);二、直接I/O文件操作這是C提供的另一種文件操作,它是通過直接存/取文件來完成對文件的處理,而上篇所說流式文件操作是通過緩衝區來進行;流式文件操作是圍繞一個FILE 指針來進行,而此類文件操作是圍繞一個文件的“句柄”來進行,什麼是句柄呢?它是一個整數,是系統用來標識一個文件(在WINDOWS中,句柄的概念擴展到所有設備資源的標識)的唯一的記號。此類文件操作常用的函數如下表,這些函數及其所用的一些符號在io.h和fcntl.h中定義,在使用時要加入相應的頭文件。

  函數 說明open() 打開一個文件並返回它的句柄close() 關閉一個句柄lseek() 定位到文件的指定位置read() 塊讀文件write() 塊寫文件eof() 測試文件是否結束filelength() 取得文件長度rename() 重命名文件chsize() 改變文件長度下面就對這些函數一一說明:1.open()打開一個文件並返回它的句柄,如果失敗,將返回一個小於0的值,原型是int open(const char *path, int access [, unsigned mode]); 參數path是要打開的文件名,access是打開的模式,mode是可選項。表示文件的屬性,主要用於UNIX系統中,在DOS/WINDOWS這個參數沒有意義。其中文件的打開模式如下表。

  符號 含義 符號 含義 符號 含義O_RDONLY 只讀方式 O_WRONLY 只寫方式 O_RDWR 讀/寫方式O_NDELAY 用於UNIX系統 O_APPEND 追加方式 O_CREAT 如果文件不存在就創建O_TRUNC 把文件長度截爲0 O_EXCL 和O_CREAT連用,如果文件存在返回錯誤 O_BINARY 二進制方式O_TEXT 文本方式對於多個要求,可以用"|"運算符來連接,如O_APPEND|O_TEXT表示以文本模式和追加方式打開文件。

  例:int handle=open("c:msdos.sys",O_BINARY|O_CREAT|O_WRITE)

  2.close()關閉一個句柄,原型是int close(int handle);如果成功返回0 .例:close(handle)

  3.lseek() 定位到指定的位置,原型是:long lseek(int handle, long offset, int fromwhere);參數offset是移動的量,fromwhere是移動的基準位置,取值和前面講的fseek()一樣,SEEK_SET:文件首部;SEEK_CUR:文件當前位置;SEEK_END:文件尾。此函數返回執行後文件新的存取位置。

  例:lseek(handle,-1234L,SEEK_CUR);//把存取位置從當前位置向前移動1234個字節。

  x=lseek(hnd1,0L,SEEK_END);//把存取位置移動到文件尾,x=文件尾的位置即文件長度4.read() 從文件讀取一塊,原型是int read(int handle, void *buf, unsigned len);參數buf保存讀出的數據,len是讀取的字節。函數返回實際讀出的字節。例:char x[200];read(hnd1,x,200);5.write()寫一塊數據到文件中,原型是int write(int handle, void *buf, unsigned len);參數的含義同read(),返回實際寫入的字節。例:char x[]="I Love You";write(handle,x,strlen(x));7.eof()類似feof(),測試文件是否結束,是返回1,否則返回0;原型是:int eof(int handle);例:while(!eof(handle1)){……};8.filelength() 返回文件長度,原型是long filelength(int handle);相當於lseek(handle,0L,SEEK_END)

  例:long x=filelength(handle);9.rename() 重命名文件,原型是int rename(const char *oldname, const char *newname); 參數oldname是舊文件名,newname是新文件名。成功返回0 .例:rename("c:config.sys","c:config.w40");10.chsize(); 改變文件長度,原型是int chsize(int handle, long size);參數size表示文件新的長度,成功返回0,否則返回-1,如果指定的長度小於文件長度,則文件被截短;如果指定的長度大於文件長度,則在文件後面補''.例:chsize(handle,0x12345);如果熟悉彙編可能會發現這種方式和彙編語言的DOS功能調用句柄式文件操作很像,比如open()就像DOS服務的3CH號功能調用,其實這種操作還有兩種類型的函數就是直接用DOS功能來完成的,如_open(),_dos_open()等等。有興趣可自已查詢BCB的幫助。

  同流式文件操作相同,這種也提供了Unicode字符操作的函數,如_wopen()等等,用於9X/NT下的寬字符編程,有興趣可自已查詢BCB的幫助。

  另外,此種操作還有lock(),unlock(),locking()等用於多用戶操作的函數,但在BCB中用得並不多,我就不介紹了,但如果要用C來寫CGI,這些就必要的常識了,如果你有這方面的要求,那就得自已好好看幫助了。

  方式                      含義"r"             打開,只讀"w"             打開,文件指針指到頭,只寫"a"             打開,指向文件尾,在已存在文件中追加"rb"            打開一個二進制文件,只讀"wb"            打開一個二進制文件,只寫"ab"            打開一個二進制文件,進行追加"r+"            以讀/寫方式打開一個已存在的文件"w+"            以讀/寫方式建立一個新的文本文件"a+"            以讀/寫方式打開一個文件文件進行追加"rb+"           以讀/寫方式打開一個二進制文件"wb+"           以讀/寫方式建立一個新的二進制文件"ab+"           以讀/寫方式打開一個二進制文件進行追加

發佈了29 篇原創文章 · 獲贊 48 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章