:本文僅供初學者參閱,解惑
- 在C程序中:
與程序代碼外的數據(文件)打交道,我們使用到流(stream)這個概念,實現進程的虛擬內存與文件之間的數據交換。
——文件流:C標准庫提供了FILE(之所以命名為FILE,因為linux將所有機制都視為文件) ,FILE對象是一個包含了管理流所需的所有信息的結構,包括緩沖區信息、各種標記(如文件結束標記和錯誤標記)以及用於實際I/O的文 件描述符等。
——輸入流,輸入流:數據從文件傳送到內存的叫輸入流,數據從內存傳送到文件的叫輸出流。
——打開文件:FILE對象通過調用fopen函數創建的。如: FILE *fp, fp=fopen("filename","r"), 表示以只讀的方式建立與filename相關的文件流;filename為當前目錄下的相對路徑名,r代表可讀(打開文件的模式)。
一:讀取
1:對一些有規范格式文件的讀取,可使用標准庫stdio.h下的fscanf函數,
函數原型為:int fscanf(FILE * stream, const char * format, [argument...])
如讀取文件data.txt(數據格式相對規范)
代碼實現讀取:
//test.c //文件讀取 #include<stdio.h> int main() { //1:創建文件流,文件指針名=fopen(文件名,使用文件方式)打開失敗則返回NULL; FILE *fp=fopen("./data.txt","r"); //以data.txt文件為例 //2:檢測文件是否打開成功; if(!fp){ printf("打開失敗!\n"); return -1; //返回異常 } //3: int num; //用來儲存一個整型數據 char name[10], place[10]; //用來儲存兩個字符串數據 //抽象理解: //理解文件位置含義:其表示已打開文件當前可讀寫字符的位置,其表示為一個到文件頭的整數; //fscanf在讀取數據時可以這樣理解:文件被打開后,它就成了一個無序字節流(水流),其會通過一個管道,流向被讀取的一端; //了解fscanf后知道,其遇到空格字符(空格,制表符),換行符,就會停止,這里的停止我們可以理解為: //停下來為文件中兩個不相關的數據塊做一個分隔的操作,剛好適應了我們一般將空字符(包括換行符)作為兩個數據之間的分隔的行為; //我們只需理解管道的兩端 //流進管道的一端的位置,就是文件的位置,表示已被讀到的位置。 //流出管道一端,就是進程用來讀取數據的一端,其可以對管道中已經做區分的數據進行讀取。 //4:讀取: fscanf(fp,"%d%s%s",&num, name,place); //fscanf對流的格式化讀取。 //注1:fscanf(fp,"%da%s%s",&num,name,place); 可以實現對數據:1a小剛 河南;的准確讀取,表示兩個數據之間以a為界。 //注2:因為流是指針的性質,所以函數是將各數據塊的首地址交給對應參數,所以num需進行&取地址操作, //注3:因為name,place本身已表達地址,所以不用改變; fscanf(fp,"\n"); //\n為控制字符,此時文件的位置到了第二行的開始; //接着進行操作:fscanf(fp,"%d%s%s",&num, name,place);就可以繼續讀取第二行 //所以我們常常只需利用一個while語句就可以將整個文件讀取到一個數據結構(進程)中 /* while(!feof(fp)) //feof()檢測一個文件是否結束,即到達文件尾,若結束,則返回非0值,否則返回0 { fscanf(fp,"%d%s%s\n",&num, name,place); } */ //檢測讀取結果 printf("%d %s %s\n",num, name, place); //關閉流 fclose(fp); return 0; }
程序運行結果:
2:從文件中讀取整行數據(標准庫stdio.h下的fgets)
函數原型:char *fgets(char *str, int n, FILE *stream);
其從指定的流 stream 讀取一行,並把它存儲在 str 所指向的字符串內。當讀取 (n-1) 個字符時,或者讀取到換行符時,或者到達文件末尾時,它會停止,遇到空格不停止;
例從文件中讀取一行數據:
代碼實現:
//test3.c //行讀取文件數據 #include<stdio.h> #define maxlen 30 int main() { //創建文件流 FILE *fp=fopen("./data.txt","r"); //2:檢測文件是否打開成功; if(!fp){ printf("打開失敗!\n"); return -1; //返回異常 } char str[maxlen];//緩沖區,用來儲存數據 //從文件中讀取一行數據,儲存到str開始的地址,最大長度為maxlen,然后下次讀取從下行開始 //如果該行的數據長於maxlen-1,則只能返回一個不完整的行,並下次調用時從該處開始 fgets(str,maxlen,fp); //檢測結果 printf("%s\n",str); //關閉流 fclose(fp); return 0; }
運行結果:
二:保存
1:保存與讀取往往相關聯,保存格式決定了你讀取的方式,使用函數fprintf可以進行指定格式的保存:
函數原型為:int fprintf( FILE *stream, const char *format, [ argument ]...)
假設保存一個人的個人信息到文件中:
/*test2.c */ //數據保存 #include<stdio.h> int main() { //例一個人的信息 int num=1; char name[10]="小明"; char place[10]="河南"; //建立與文件的流 FILE *fp=fopen("./data.txt","w"); //2:檢測文件是否打開成功; if(!fp){ printf("打開失敗!\n"); return -1; //返回異常 } //將數據格式化輸出到指定文件流,int fprintf( FILE *stream, const char *format, [ argument ]...) //注:此函數,是將format字符串寫入到指定輸出流中,format包括空格字符,非空格字符,說明符之中的一個或多個。如:fprintf(fp," "); 就是將空格輸入到流中。 //可理解為進程借助流將數據打印(fprintf)到了文件中; //將個人信息,寫入指定流中,數據間以一個空格分隔,最后還寫入換行符(控制字符)。 fprintf(fp,"%d %s %s\n",num, name,place); //所以常常只要利用一個while語句就可以將講一個表(鏈表,順序表)按指定行格式寫入輸出流中 /* while(!feof(fp)) //feof()檢測一個文件是否結束,即到達文件尾,若結束,則返回非0值,否則返回0 { fprintf(fp,"%d %s %s\n",num, name,place); } */ //關閉流 fclose(fp); return 0; }
運行結果:
2:寫一個字符串到流中(fputs),函數原型:int fputs(const char *str, FILE *stream);
例:
//test4.c //保存字符串 #include<stdio.h> int main() { //1:創建文件流,文件指針名=fopen(文件名,使用文件方式)打開失敗則返回NULL; FILE *fp=fopen("./data.txt","a"); //以data.txt文件為例,a表示追加 //2:檢測文件是否打開成功; if(!fp){ printf("打開失敗!\n"); return -1; //返回異常 } //string char string[20]="Facing the world"; //write string to the fstream fputs(string,fp); //關閉流 fclose(fp); return 0; }
運行結果:
淺談c++:
在c++中我們可以使用操作符<<, >>來進行流的讀寫操作,更加的方便和易於理解;
具體參考下列實例:
1:讀取所示數據:
代碼實現:
//c++文件讀取 #include<iostream> //輸入輸出流 #include<fstream> //文件流 //using namespace std; //若使用該聲明,則可以不用在使用的每個標准庫的成員前加std:: int main() { //序號,年齡,年; int num, age, year; //姓名,地址 char name[20], place[20]; //c++的文件流,ifstream為輸入文件流 std::ifstream fp; //open為ifstream的成員函數,功能為打開文件,並將它與流關聯 fp.open("./data.txt",std::ios::in); //ios::in表示讀流的方式,表示打開模式。 //成員函數is_open檢查流是否有關聯文件,即打開成功與否,成功返回true,失敗返回false if(!fp.is_open()){ std::cout<<"打開文件失敗!!\n"; return 1; // 返回異常; } //讀取數據 fp>>num>>year>>age>>name>>place; //使用操作符>>,將數據傳輸到對應的變量中 //檢測 std::cout<<num<<":"<<name<<",age:"<<age<<",year:"<<year<<",live in:"<<place<<"\n"; //cout相當於printf //關閉流 fp.close(); return 0; }
運行結果:
2:往文件保存數據:
實例:保存一個人的具體信息到文件data.txt中
代碼實現:
//c++數據保存 #include<iostream> //輸入輸出流 #include<fstream> //文件流 //using namespace std; //若使用該聲明,則可以不用在使用的每個標准庫的成員前加std:: int main() { //序號,年齡,年; int num=3; int age=20; int year=1993; //姓名,地址 char name[20]="小龍"; char place[20]="廣元"; //c++的文件流,ofstream為輸出文件流 std::ofstream fp; //open為ofstream的成員函數,功能為打開文件,並將它與流關聯 fp.open("./data.txt",std::ios::app); //ios::app表示每次寫入是都追加到流尾,表示打開模式。 //成員函數is_open檢查流是否有關聯文件,即打開成功與否,成功返回true,失敗返回false if(!fp.is_open()){ std::cout<<"打開文件失敗!!\n"; return 1; // 返回異常; } //讀取數據 fp<<num<<" "<<year<<" "<<age<<" "<<name<<" "<<place<<"\n"; //使用操作符<<,將各數據傳輸到流所關聯的文件中 //關閉流 fp.close(); return 0; }
運行結果: