1. 程式人生 > >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(0成功的開啟一個檔案時,該函式將返回一個FILE指標,如果檔案開啟失敗,將返回一個NULL指標。如想開啟test檔案,進行寫:
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值。常用以下方法進行測試:
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 fgetchar(void);
int fputc(int ch,FILE *stream);
int fputchar(int ch);
int getc(FILE *stream);
int putc(int ch,FILE *stream);
其中fgetc()函式將把由流指標指向的檔案中的一個字元讀出,例如:
ch=fgetc(fp);
將把流指標fp指向的檔案中的一個字元讀出,並賦給ch,當執行fgetc()函式時,若當時檔案指標指到檔案尾,即遇到檔案結束標誌EOF(其對應值為-1),該函式返回一個-1給ch,在程式中常用檢查該函式返回值是否為-1來判斷是否已讀到檔案尾,從而決定是否繼續。
#include stdio.h
main()
{
FILE *fp;
ch ch;
if((fp=fopen(myfile.tex,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()等價於fput(),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個字元,讀到由指標stream指向的字元陣列中去,例如:
fgets(buffer,9,fp);
將把fp指向的檔案中的8個字元讀到buffer記憶體區,buffer可以是定義的字元陣列,也可以是動態分配的記憶體區。
注意,fgets()函式讀到'\n'就停止,而不管是否達到數目要求。同時在讀取字串的最後加上'\0'。
fgets()函式執行完以後,返回一個指向該串的指標。如果讀到檔案尾或出錯,則均返回一個空指標NULL,所以長用feof()函式來測定是否到了檔案尾或者是ferror()函式來測試是否出錯,例如下面的程式用fgets()函式讀test.txt檔案中的第一行並顯示出來:
#include stdio.h
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裡輸入一些字元:
#include 
main() 
{ 
char *s=That's good news; 
int i=617;
FILE *fp;
fp=fopne(test.dat, w); /*建立一個文字檔案只寫*/ 
fputs(Your score of TOEFLis,fp); /*向所建檔案寫入一串字元*/ 
fputc(':', fp); /*向所建檔案寫冒號:*/ 
fprintf(fp, %d\n, i); /*向所建檔案寫一整型數*/ 
fprintf(fp, %s, s); /*向所建檔案寫一字串*/ 
fclose(fp);
} 
用DOS的TYPE命令顯示TEST.DAT的內容如下所示: 
螢幕顯示 
Your score of TOEFL is: 617
That's good news
下面的程式是把上面的檔案test.dat裡的內容在螢幕上顯示出來:
#include 
main() 
{ 
char *s, 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);
getch();
} 
執行後螢幕顯示: 
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()相同。

總結:到此!C語言入門基礎就算是到尾聲了!祝大家學習進步!

相關推薦

C語言入門檔案操作

檔案操作 一、標準檔案的讀寫1.檔案的開啟fopen() 檔案的開啟操作表示將給使用者指定的檔案在記憶體分配一個FILE結構區,並將該結構的指標返回給使用者程式,以後使用者程式就可用此FILE指標來實現對指定檔案的存取操作了。當使用開啟函式時,必須給出檔名、檔案操作方式(讀

C語言入門之列舉

C語言中,列舉就是專門用於表示幾種固定型別的取值。列舉的本質就是基本資料型別, 就是整形。 列舉和結構體一樣, 要想定義列舉型別變數, 那麼必須先定義列舉型別。 列舉型別定義的格式   enum 列舉型別名稱 { 取值, }; // 1.

C#編程----------接口

目的 count() 聲明變量 form [] 類的繼承 計算機 構造 執行 接口 如果一個類派生自一個接口,聲明這個類就會實現某些函數.並不是所有的面向對象的語言都支持接口. 例如,有一個接口:IDispoable,包含一個方法Dispose(),該方法又類實現,用於清理

C之數組

C語言 數組 在 C 語言中,我們不可避免的要接觸到數組。我們就來看看數組是什麽玩意,其實數組就是相同類型的變量的有序集合。下面這張圖更加形象的表示出數組的含義 數組在一片連續的內存空間中存儲元素,數組元素的個數是可以顯示或隱式指定的。比如: int a[5] = {1,

C++語言學習——自定義內存管理

single null allocated 析構函數 opera .get cat st2 argc C++語言學習(二十)——自定義內存管理 一、統計類對象中成員變量的訪問次數 mutable是為了突破const函數的限制而設計的,mutable修飾的成員變量將永遠處於可

ElasticSearch最佳入門實踐mget批量查詢api

1、批量查詢的好處 就是一條一條的查詢,比如說要查詢100條資料,那麼就要傳送100次網路請求,這個開銷還是很大的 如果進行批量查詢的話,查詢100條資料,就只要傳送1次網路請求,網路請求的效能開銷縮減100倍 2、mget的語法 可以說mget是很重要

Java 從入門到進階之路

在之前的文章我們介紹了一下 Java 中的  集合框架中的Collection 的子介面 List的 增刪改查和與陣列間相互轉換的方法,本章我們來看一下 Java 集合框架中的Collection 的子介面 List 的另外一些方法。 我們在使用集合的時候難免會對其中的元素進行排序,因為 Set 集

【轉】JMeter學習HTTP屬性管理器HTTP Cookie Manager、HTTP Request Defaults

agen 讀取 expired fault 範圍 運行時 ear 定制 只有一個 Test Plan的配置元件中有一些和HTTP屬性相關的元件:HTTP Cache Manager、HTTP Authorization Manager、HTTP Cookie Manager

2016集訓測試賽小結

時間 第一題 是我 很多 分析 題目 ... 人的 簡單   這場測試賽有必要小結一下.   昨晚 1 點才睡, 今天狀態很差, 先睡了 1 個小時, 然後開始打比賽. 第一題不大會做, 寫了一個代碼後發現是錯的, 第二題看不懂題, 第三題簡單地分析了一下, 發現是一個樹形

C#編程----------修飾符

宋體 public ext str 繼承 應用 man 空間 layout 修飾符 修飾符即應用於類型或成員的關鍵字.修飾符可以指定方法的可見性,如public或private,還可以指定一項的本質,如剛發的vritual或abstract. 可見性的修飾符 修

企業分布式微服務雲SpringCloud SpringBoot mybatis 集成swagger2構建Restful API

sel ima eth syn conf ring 但是 batis 關註 一、引入依賴 <dependency> <groupId>io.springfox</groupId> <

Linux學習筆記shell特殊符號、 sort_wc_uniq、tee_tr_split

tee_tr_split命令一、特殊字符 1.‘* ‘任意個任意字符‘? ‘任意一個字符‘# ‘註釋字符‘ \ ‘脫義字符‘ | ‘管道符其中大部分之前都用過,對於脫義符‘\‘脫義符用法舉例如圖 2.幾個與管道有關的命令cut 分割,-d 分隔符 -f 指定段號 -c 指定第幾個字符 sort 排序,

Linux 學習總結 系統管理4

iptables filter nat netfilter iptables 應用實例 一 filter表案例 1 需求:只針對filter表,預設INPUT 鏈DROP ,其他兩個鏈ACCEPT,然後針對192.169.188.0/24開通22端口,對所有網段開放80端口,21端口。我們編寫sh

大數據筆記——Scala函數式編程

=== 情況 不能 nbsp 結構 map som class 編程 ===================== Scala函數式編程 ======================== 一、Scala中的函數 (*) 函數是Scala中的頭等公民,就和數字一樣,可以在變量中

python2.7練習小例子

點贊 實例 net mil 感覺 format 經典題目 tty 遞推 25):題目:有5個人坐在一起,問第五個人多少歲?他說比第4個人大2歲。問第4個人歲數,他說比第3個人大2歲。問第三個人,又說比第2人大兩歲。問第2個人,說比第一個人大兩歲。最後問第一個人,他說

完善的復數類

C++ 復數類 賦值操作符 操作符重載 我們在之前已經是實現了復數類的相加操作,那麽我們今天就來完善下復數類。一個完整的復數類應該具備的操作有:運算(+, -, *, /);比較(==, !=);賦值(=);求模(modulus);利用的就是操作符重載來統一實現復數與實數的運算

初探 C++ 標準庫

C++ 標準庫 cout cin 操作符重載 今天我們來看下 C++ 中的標準庫,這幾天我們一直學習的是 C++ 中的一大難點,操作符重載。那麽我們想想操作符左移 << 可以重載嗎?操作符 << 的原生語義是按位左移,如:1 << 2,則

類的加載

main函數 img emp ima info 技術 admin file bubuko jvm先找main函數,加載Demo34類 加載Car類,實例化對象進堆,成員變量都在堆中執行。類中的函數依舊在占中運行,遵循先入後出的原則,執行結束立即撤

Kafka:ZK+Kafka+Spark Streaming集群環境搭建Structured Streaming:同一個topic中包含一組數據的多個部分,按照key它們拼接為一條記錄以及遇到的問題

eas array 記錄 splay span ack timestamp b- each 需求: 目前kafka的topic上有一批數據,這些數據被分配到9個不同的partition中(就是發布時key:{m1,m2,m3,m4...m9},value:{records

MySQL數據庫8變量作用域

圖片 沒有 http global 而且 局部作用域 數據庫 過程 會話 變量作用域 變量作用域:變量能夠使用的區域範圍 局部作用域 使用declare關鍵字聲明(在結構體內:函數/存儲過程/觸發器),而且只能在結構體內部使用。 declare關鍵字聲明的變量沒有任何符號修