C++ 文件操作


 

目錄

需要了解的概念
文件操作主要函數
例子

 


 

需要了解的概念

[數據流][緩沖區(Buffer)][文件類型][文件存取方式][借助文件指針讀寫文件]

需要理解的知識點包括:數據流、緩沖區、文件類型、文件存取方式

1.1 數據流:

指程序與數據的交互是以流的形式進行的.進行C語言文件的存取時,都會先進行“打開文件”操作,這個操作就是在打開數據流,而“關閉文件”操作就是關閉數據流

1.2 緩沖區(Buffer):

指在程序執行時,所提供的額外內存,可用來暫時存放做准備執行的數據.它的設置是為了提高存取效率,因為內存的存取速度比磁盤驅動器快得多.
C++ 語言中帶緩沖區的文件處理:
C++ 語言的文件處理功能依據系統是否設置“緩沖區”分為兩種:

  • 一種是設置緩沖區
  • 另一種是不設置緩沖區

由於不設置緩沖區的文件處理方式,必須使用較低級的I/O函數(包含在頭文件io.h和fcntl.h中)來直接對磁盤存取,這種方式的存取速度慢,並且由於不是 C++ 的標准函數,跨平台操作時容易出問題.下面只介紹第一種處理方式,即設置緩沖區的文件處理方式:
當使用標准 I/O 函數(包含在頭文件 cstdio 中)時,系統會自動設置緩沖區,並通過數據流來讀寫文件.
當進行文件讀取時,不會直接對磁盤進行讀取,而是先打開數據流,將磁盤上的文件信息拷貝到緩沖區內,然后程序再從緩沖區中讀取所需數據,如下圖所示:

事實上,當寫入文件時,並不會馬上寫入磁盤中,而是先寫入緩沖區,只有在緩沖區已滿或“關閉文件”時,才會將數據寫入磁盤,如下圖所示.

1.3 文件類型:

分為文本文件二進制文件兩種.

  • 文本文件:  是以字符編碼的方式進行保存的,只是計算機以二進制表示數據在外部存儲介質上的另一種存放形式.它所存放的每一個字節都可以轉換為一個可讀字符當向文件中寫入數據時,一旦遇到"換行"字符(ASCII 碼為10)則會轉換成"回車-換行"(ASCII 值為13,10).在讀取數據的時候,一遇到"回車-換行"的組合 ASCII 值為13,10),則會轉換成為"換行"字符(ASCII 碼為10)
  • 二進制文:  件將內存中數據原封不動的讀取和寫入文件中

二進制文件適用於非字符為主的數據.如果以記事本打開,只會看到一堆亂碼.
當按照文本方式其實,除了文本文件外,所有的數據都可以算是二進制文件.二進制文件的優點在於存取速度快,占用空間小,以及可隨機存取數據.
在文件操作中因為文本打開方式和二進制文件打開方式會導致數據讀取和寫入換行時候的不同所以在進行文件操作時候要注意寫入和讀取的方式要保持一致,如果采用文本方式寫入,應該采用文本方式讀取,如果采用二進制方式寫入,就應該用二進制方式讀取,但是不管是文本文件還是二進制文件,如果采用統一的二進制方式寫入和讀取數據都是不會出錯的,不管是文本文件還是二進制文件,都可以采用二進制方式或者文本方式打開,然后進行寫入或讀取.但是對於二進制文件來說,如果以文本凡是讀取數據時候可能會出現一些問題

1.4 文件存取方式:

包括順序存取方式隨機存取方式兩種.

  • 順序讀取也就是從上往下,一筆一筆讀取文件的內容.保存數據時,將數據附加在文件的末尾.這種存取方式常用於文本文件,而被存取的文件則稱為順序文件.
  • 隨機存取方式多半以二進制文件為主.它會以一個完整的單位來進行數據的讀取和寫入,通常以結構為單位.

1.5 借助文件指針讀寫文件

我們如果要訪問文件,要借助於文本變量,即文件指針才可以完成
文件在進行讀寫操作之前要先打開,使用完畢要關閉.所謂打開文件,實際上是建立文件的各種有關信息,並使文件指針指向該文件,以便進行其它操作.關閉文件則斷開指針與文件之間的聯系,也就禁止再對該文件進行操作.

1.6 操作流圖

[返回目錄]


 

文件操作主要函數

[文件打開與關閉][文件的讀寫][文件的緩沖區操作][文件的其他操作]

2.1 文件打開與關閉

[fopen][fclose]

2.1.1 fopen(打開文件)

頭文件: #include<cstdio>

函數聲明: FILE * fopen(const char * path,const char * mode);

參數:

  • path字符串 包含欲打開的文件路徑及文件名如果沒有指定文件路徑,則默認為當前工作目錄
  • mode字符串

使用方式 具體含義              
“rt”    只讀打開一個文本文件,只允許讀數據
“wt”     只寫打開或建立一個文本文件,只允許寫數據
“at”   追加打開一個文本文件,並在文件末尾寫數據
“rb”     只讀打開一個二進制文件,只允許讀數據
“wb”    只寫打開或建立一個二進制文件,只允許寫數據
“ab”     追加打開一個二進制文件,並在文件末尾寫數據
“rt+”   讀寫打開一個文本文件,允許讀和寫
“wt+”   讀寫打開或建立一個文本文件,允許讀寫
“at+”   讀寫打開一個文本文件,允許讀,或在文件末追加數據
“rb+”   讀寫打開一個二進制文件,允許讀和寫
“wb+”   讀寫打開或建立一個二進制文件,允許讀和寫
“ab+”   讀寫打開一個二進制文件,允許讀,或在文件末追加數據

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

  • r(read): 讀 (打開只讀文件,該文件必須存在)
  • w(write): 寫 (打開只寫文件,若文件存在則文件長度清為0,即該文件內容會消失.若文件不存在則建立該文件)
  • a(append): 追加(以附加的方式打開只寫文件.若文件不存在,則會建立該文件,如果文件存在,寫入的數據會被加到文件尾,即文件原先的內容會被保留)
  • t(text): 文本文件,可省略不寫
  • b(banary): 二進制文件
  • +: 可讀和寫

說明:

  • 上述的形態字符串都可以再加一個 b 字符,如 rb、w+b 或 ab+ 等組合,加入 b 字符用來告訴函數庫打開的文件為二進制文件,而非純文字文件.不過在 POSIX 系統,包含 Linux 都會忽略該字符.由 fopen() 所建立的新文件會具有 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH(0666) 權限,此文件權限也會參考 umask 值.
  • 使用 fopen() 函數打開的文件會先將文件復制到緩沖區.注意:所下達的讀取或寫入動作,都是針對緩沖區進行存取而不是磁盤,只有當使用 fclose() 函數關閉文件時,緩沖區中的數據才會寫入磁盤.

返回值:  文件順利打開后,指向該流的文件指針就會被返回.若果文件打開失敗則返回 NULL , 並把錯誤代碼存在 errno 中.(附加說明 一般而言,開文件后會作一些文件讀取或寫入的動作,若開文件失敗,接下來的讀寫動作也無法順利進行,所以在 fopen() 后請作錯誤判斷及處理.)

2.1.2 fclose(關閉文件)

頭文件: #include<cstdio>

函數聲明: int fclose(FILE * stream);

說明: fclose() 用來關閉先前 fopen() 打開的文件.此動作會讓緩沖區內的數據寫入文件中,並釋放系統所提供的文件資源.

返回值:

  • 若關文件動作成功則返回 0 ,有錯誤發生時則返回 EOF 並把錯誤代碼存到 errno.
  • 錯誤代碼 EBADF 表示參數 stream 非已打開的文件.

[返回子目錄]

2.2 文件的讀寫

[fgetc][fputc][fgets][fputs][fread][fwrite][fprintf 與 fscanf][getc][getchar][gets][putc][putchar][puts][ungetc]

對文件的讀和寫是最常用的文件操作.在C語言中提供了多種文件讀寫的函數:(使用以下函數都要求包含頭文件cstdio.)

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

2.2.1 fgetc (由文件中讀取一個字符)

頭文件: include<cstdio>

函數聲明: int fgetc(FILE * stream);

說明:

  • fgetc()從參數stream所指的文件中讀取一個字符.若讀到文件尾而無數據時便返回EOF.
  • 字符讀取函數fgetc()可從文件數據流中一次讀取一個字符,然后讀取光標移動到下一個字符,並逐步將文件的內容讀出

例子解析:


int ch; 

ch=fgetc(fp);

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

對於fgetc函數的使用有以下幾點說明:

  • 在fgetc函數調用中,讀取的文件必須是以讀或讀寫方式打開的.
  • 讀取字符的結果也可以不向字符變量賦值 (例如:  fgetc(fp); 但是讀出的字符不能保存)
  • 在文件內部有一個位置指針,用來指向文件的當前讀寫字節位置,在文件打開時,該指針總是指向文件的第一個字節.使用fgetc 函數后,該位置指針將向后移動一個字節. 因此可連續多次使用fgetc函數,讀取多個字符.

應注意文件指針和文件內部的位置指針不是一回事.

  • 文件指針是指向整個文件的,須在程序中定義說明,只要不重新賦值,文件指針的值是不變的.
  • 文件內部的位置指針用以指示文件內部的當前讀寫位置,每讀寫一次,該指針均向后移動,它不需在程序中定義說明,有系統自動設置而是的.

返回值 : getc() 會返回讀取到的字符,若返回 EOF 則表示到了文件尾

2.2.2 fputc(將一指定字符寫入文件流中)

頭文件: #include<cstdio>

函數聲明: int fputc(int c,FILE * stream);

說明:

  • fputc 會將參數c 轉為 unsigned char 后寫入參數 stream 指定的文件中.
  • 其意 putc 函數的使用幾點說明:
    • 被寫入的文件可以用寫、讀寫、追加方式打開,用寫或讀寫方式,寫入字符時是從文件首開始的.如需保留原有文件內容,希望寫入的字符,被寫入的文件若不存在,則創建該文件.
    • 每寫入一個字符,文件內部位置指針向后移動一個字節.
    • fputc 函數有一個返回值,如寫入成功則返回寫入的字符,否則返回一個 EOF .可用此來判斷寫符,寫入一個文件,再把該文件內容讀出顯示在屏幕上.


返回值: fputc() 會返回寫入成功的字符,即參數 c.若返回 EOF 則代表寫入失敗.

2.2.3 fgets(由文件中讀取一字符串)

頭文件: #include<cstdio>

函數聲明: char * fgets(char * s,int size,FILE * stream);

說明: fgets() 用來從參數 stream 所指的文件內讀入字符並存到參數 s 所指的內存空間,直到出現換行字符、讀到文件尾或是已讀了size-1個字符為止,最后會加上 NULL 作為字符串結束.

返回值: gets() 若成功則返回 s 指針,返回 NULL 則表示有錯誤發生.  

2.2.4 fputs(將一指定的字符串寫入文件內)

頭文件: #include<cstdio>

函數聲明: int fputs(const char * s,FILE * stream);

說明: fputs() 用來將參數 s 所指的字符串寫入到參數 stream 所指的文件內.

返回值: 若成功則返回寫出的字符個數,返回 EOF 則表示有錯誤發生.

2.2.5 fread(從文件流讀取數據)

頭文件: #include<cstdio>

函數聲明: size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream);

說明: fread() 用來從文件流中讀取數據

參數:

  • stream 為已打開的文件指針
  • ptr 指向欲存放讀取進來的數據空間,讀取的字符數以參數 size*nmemb 來決定.Fread() 會返回實際讀取到的 nmemb 數目,如果此值比參數 nmemb 來得小,則代表可能讀到了文件尾或有錯誤發生,這時必須用 feof() 或 ferror() 來決定發生什么情況.

返回值: 返回實際讀取到的nmemb數目.

2.2.6 fwrite(將數據寫至文件流)

頭文件: #include<cstdio>

函數聲明: size_t fwrite(const void * ptr,size_t size,size_t nmemb,FILE * stream);

說明: 

  • fwrite() 用來將數據寫入文件流中
  • fprintf 和 fscanf 函數的讀寫對象不是終端(標准輸入輸出),而是磁盤文件

參數:

  • stream 為已打開的文件指針
  • ptr 指向欲寫入的數據地址,總共寫入的字符數以參數 size*nmemb 來決定.Fwrite() 會返回實際寫入的 nmemb 數目.

返回值: 返回實際寫入的 nmemb 數目.

2.2.7 fprintf 與 fscanf(將指定字符寫磁盤文件)

函數聲明:

  • _CRTIMP int __cdecl fprintf(FILE *, const char *, ...);
  • _CRTIMP int __cdecl fscanf(FILE *, const char *, ...);

說明: 它們與 printf 和 scanf 函數相仿,都是格式化讀寫函數.不同的是:fprintf 和 fscanf 函數的讀寫對象不是終端(標准輸入輸出),而是磁盤文件.printf 函數是將內容輸出到終端(屏幕),因此,fprintf 就是將內容輸出到磁盤文件了

2.2.8 getc(由文件中讀取一個字符)

頭文件: #include<cstdio>

函數聲明: int getc(FILE * stream);

說明: 

  • getc() 用來從參數 stream 所指的文件中讀取一個字符.若讀到文件尾而無數據時便返回 EOF
  • getc() 與 fgetc() 作用相同,但 getc() 為宏定義,非真正的函數調用.

返回值: getc() 會返回讀取到的字符,若返回 EOF 則表示到了文件尾.

2.2.9 getchar(由標准輸入設備內讀進一字符)

頭文件: #include<cstdio>

函數聲明: int getchar(void);

說明: 

  • getchar() 用來從標准輸入設備中讀取一個字符.然后將該字符從 unsigned char 轉換成 int 后返回
  • getchar() 非真正函數,而是 getc(stdin) 宏定義

返回值: getchar()會返回讀取到的字符,若返回EOF則表示有錯誤發生.

2.2.10 gets(由標准輸入設備內讀進一字符串)

頭文件: #include<cstdio>

函數聲明: char * gets(char *s);

說明: gets() 用來從標准設備讀入字符並存到參數 s 所指的內存空間,直到出現換行字符或讀到文件尾為止,最后加上 NULL 作為字符串結束,由於 gets() 無法知道字符串 s 的大小,必須遇到換行字符或文件尾才會結束輸入,因此容易造成緩沖溢出的安全性問題.建議使用 fgets() 取代

返回值: gets() 若成功則返回 s 指針,返回 NULL 則表示有錯誤發生.

2.2.11 putc(將一指定字符寫入文件中)

頭文件: #include<cstdio> 

函數聲明: int putc(int c,FILE * stream);

說明:

  • putc() 會將參數 c 轉為 unsigned char 后寫入參數 stream 指定的文件中
  • putc() 與 fputc()作用相同,但 putc() 為宏定義,非真正的函數調用.

返回值: putc() 會返回寫入成功的字符,即參數 c.若返回 EOF 則代表寫入失敗.

2.2.12 putchar(將指定的字符寫到標准輸出設備)

頭文件: #include<cstdio>

函數聲明: int putchar (int c);

說明:

  • putchar() 用來將參數 c 字符寫到標准輸出設備.
  • putchar() 非真正函數,而是 putc(c,stdout) 宏定義.

返回值: putchar() 會返回輸出成功的字符,即參數 c.若返回 EOF 則代表輸出失敗.

2.2.13 puts(由標准輸入設備內讀進一字符串)

頭文件: #include<cstdio>

函數聲明: int puts(char *s);

說明:  把函數的字符串寫到標准輸出流 stdout,在輸出流中用換行符('\n')替換字符串中的結束符null 字符('\0 ') 

返回值: puts() 若成功則返回正的非零值,返回 EOF 則表示有錯誤發生.

2.2.14 ungetc(將指定字符寫回文件流中)

頭文件: #include<cstdio>

函數聲明: int ungetc(int c,FILE * stream);

說明: ungetc() 將參數 c 字符寫回參數 stream 所指定的文件流.這個寫回的字符會由下一個讀取文件流的函數取得.

返回值: 成功則返回 c 字符,若有錯誤則返回 EOF.

[返回子目錄]

2.3 文件的緩沖區操作:

[fflush] [setbuf] [setbuffer] [setlinebuf] [setvbuf]

2.3.1 fflush(更新緩沖區)

頭文件: #include<cstdio>

函數聲明: int fflush(FILE* stream);

說明: fflush() 會強迫將緩沖區內的數據寫回參數 stream 指定的文件中.如果參數 stream 為 NULL ,fflush() 會將所有打開的文件數據更新.

返回值: 成功返回 0 ,失敗返回 EOF ,錯誤代碼存於errno中.(錯誤代碼: EBADF 參數 stream 指定的文件未被打開,或打開狀態為只讀)

2.3.2 setbuf(設置文件流的緩沖區)

頭文件: #include<cstdio>

函數聲明: void setbuf(FILE * stream,char * buf);

說明: 在打開文件流后,讀取內容之前,調用 setbuf() 可以用來設置文件流的緩沖區

參數:

  • stream為指定的文件流
  • buf 指向自定的緩沖區起始地址.如果參數 buf 為 NULL 指針,則為無緩沖 IO .Setbuf() 相當於調用 setvbuf(stream,buf,buf?_IOFBF:_IONBF,BUFSIZ)

2.3.3 setbuffer(設置文件流的緩沖區)

頭文件: #include<cstdio>

函數聲明: void setbuffer(FILE * stream,char * buf,size_t size);

說明: 在打開文件流后,讀取內容之前,調用 setbuffer() 可用來設置文件流的緩沖區.

參數:

  • stream 為指定的文件流
  • buf 指向自定的緩沖區起始地址
  • size 為緩沖區大小

2.3.4 setlinebuf(設置文件流為線性緩沖區)

頭文件: #include<cstdio>

函數聲明: void setlinebuf(FILE * stream);

說明: setlinebuf() 用來設置文件流以換行為依據的無緩沖 IO.相當於調用 setvbuf(stream,(char * )NULL,_IOLBF,0); 

2.3.5 setvbuf(設置文件流的緩沖區)

頭文件: #include<cstdio>

函數聲明: int setvbuf(FILE * stream,char * buf,int mode,size_t size);

說明: 在打開文件流后,讀取內容之前,調用 setvbuf() 可以用來設置文件流的緩沖區

參數:

  • stream 為指定的文件流
  • buf 指向自定的緩沖區起始地址
  • size 為緩沖區大小
  • mode取值有下列幾種:
    • _IONBF 無緩沖 IO
    • _IOLBF 以換行為依據的無緩沖 IO
    • _IOFBF 完全無緩沖 IO.如果參數 buf 為 NULL 指針,則為無緩沖 IO

[返回子目錄]

2.4 文件的其他操作:

[fseek] [ftell] [rewind] [clearerr] [fdopen] [feof] [fileno] [freopen

2.4.1 fseek(移動文件流的讀寫位置)

頭文件: #include<cstdio>

函數聲明: int fseek(FILE * stream,long offset,int whence);

說明: 

  • fseek() 用來移動文件流的讀寫位置
  • fseek() 不像 lseek() 會返回讀寫位置,因此必須使用ftell()來取得目前讀寫的位置

參數:

  • stream 為已打開的文件指針
  • offset 為根據參數whence來移動讀寫位置的位移數(offset 為整數時往后移, 為復數時往前移)
  • whence為下列其中一種:
    • SEEK_SET 從距文件開頭offset位移量為新的讀寫位置
    • SEEK_CUR 以目前的讀寫位置往后增加offset個位移量
    • SEEK_END 將讀寫位置指向文件尾后再增加offset個位移量。

返回值: 當調用成功時則返回0,若有錯誤則返回-1,errno會存放錯誤代碼。

2.4.2 ftell(取得文件流的讀取位置)

頭文件: #include<cstdio>

函數聲明: long ftell(FILE * stream);

說明: ftell() 用來取得文件流目前的讀寫位置

返回值: 當調用成功時則返回目前的讀寫位置,若有錯誤則返回 -1,errno 會存放錯誤代碼(錯誤代碼: EBADF 參數 stream 無效或可移動讀寫位置的文件流)

2.4.3 rewind(重設文件流的讀寫位置為文件開頭)

頭文件: #include<cstdio>

函數聲明: void rewind(FILE * stream);

說明: rewind() 用來把文件流的讀寫位置移至文件開頭。參數 stream 為已打開的文件指針。此函數相當於調用 fseek(stream,0,SEEK_SET)。

2.4.4 clearerr(清除錯誤旗標)

頭文件: #include<cstdio>

函數聲明: void clearerr(FILE * stream);

說明: clearerr() 清除 stream 指定的文件流所使用的錯誤旗標。

2.4.5 fdopen(將文件描述詞轉為文件指針)

頭文件: #include<cstdio>

函數聲明: FILE * fdopen(int fildes,const char * mode);

說明: fdopen()會將參數fildes 的文件描述詞,轉換為對應的文件指針后返回

參數: mode 字符串則代表着文件指針的流形態,此形態必須和原先文件描述詞讀寫模式相同。關於mode 字符串格式請參考fopen()。

返回值: 轉換成功時返回指向該流的文件指針。失敗則返回NULL,並把錯誤代碼存在errno中。

2.4.6 feof(檢查文件流是否讀到了文件尾)

頭文件: #include<cstdio>

函數聲明: int feof(FILE * stream);

說明: feof()用來偵測是否讀取到了文件尾,尾數stream為fopen()所返回之文件指針。如果已到文件尾則返回非零值,其他情況返回0。

返回值: 返回非零值代表已到達文件尾。 

2.4.7 fileno(返回文件流所使用的文件描述詞)

頭文件: #include<cstdio>

函數聲明: int fileno(FILE * stream);

說明: fileno()用來取得參數stream指定的文件流所使用的文件描述詞。

返回值: 返回文件描述詞

2.4.8 freopen(打開文件)

頭文件: #include<cstdio>

函數聲明: FILE * freopen(const char * pathconst char * mode,FILE * stream);

說明: Freopen()會將原stream所打開的文件流關閉,然后打開參數path的文件。

參數: 

  • path 字符串包含欲打開的文件路徑及文件名
  • mode 請參考fopen()說明
  • stream 為已打開的文件指針

[返回目錄]


 

例子

用有關文件寫入函數寫一個復制文件的程序

View Code
#include <iostream>
#include <cstdio>
#include <string>
using namespace std;  

void main()  
{
    while(true)
    {
        string filepath;
        int length;
        FILE *source,*destination;
        cout<<"請輸入要復制的文件路徑(包括執行文件名和文件后綴名):\n";
        cin>>filepath;
        source = fopen(filepath.data(),"rb");
        if(source == NULL)
        {
            cout<<"打開文件失敗!從新";
            continue;
        }
        fseek(source,0,SEEK_END);
        length = ftell(source);
        char* data = new char[length];
        rewind(source);
        fread((void*)data,sizeof(char),length,source);
        cout<<"請輸入文件粘貼路徑(包括執行文件名和文件后綴名):\n";
        cin>>filepath;
        destination = fopen(filepath.data(),"wb");
        if(destination == NULL)
        {
            delete data;
            cout<<"寫入文件失敗!"<<endl;
            fclose(source);
            continue;
        }
        fwrite((void*)data,sizeof(char),length,destination);
        fclose(destination);
        fclose(source);
        delete data;
        cout<<"關閉文件成功"<<endl;
        break;
    }

    system("pause");  
}


免責聲明!

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



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