在C語言中有兩個常見的保存文件的函數:fprintf 與 fwrite。其主要用法與差異歸納如下:
一、fprintf函數。
1.以文本的形式保存文件。函數原型為 int fprintf(FILE* stream,const char* format,[argument]),用法類似於printf函數,返回值是輸出的字符數,發生錯誤時返回一個負值。
2.對應的讀取函數為fscanf()。函數原型為int fscanf(FILE* stream,const char* format,[argument...]),用法類似於scanf函數,返回值為成功讀入參數的個數,當讀到文件末尾EOF時,返回-1。
二、fwrite函數。
1.以二進制形式保存文件。函數原型為size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream),參數依次為數據地址,數據元素大小,數據元素個數,文件指針。返回值為實際寫入的數據的項數。
2.對應的讀取函數為fread。函數原型為size_t fread ( void *buffer, size_t size, size_t count, FILE *stream) ,參數依次為數據地址,數據元素大小,數據元素個數,文件指針。返回值為實際讀取的數據項數,當讀到文件末尾的EOF時,返回0。
三、疑難點:
1.由於fprintf以文本形式保存文件,所以當保存多組數據的時候,每組數據之間必須有分隔符,可以是空格,換行符或者特殊字符,否則在讀取文件的時候會出錯。
2.無論哪種讀取文件的方式,都可以用while(!feof(fp))來判斷文件是否讀到末尾,但feof()函數在讀到EOF時仍然返回0,到下一個位置時才返回1,這就容易導致最后一組數據容易讀取兩次,或多讀取一組空數據。(經試驗fprint函數以空格和換行符作為數據分隔符的時候不會出現此情況)利用兩個讀取函數的返回值,我們可以避免這種情況。
2.1 fscanf()函數避免多讀最后一行:
1 Node* readTxt(){ 2 FILE* fp = NULL; 3 Node* head = NULL; 4 fp = fopen("file.txt","r"); 5 if(fp == NULL){ 6 cout<<"Error(fopen):fp == NULL"<<endl; 7 return NULL; 8 } 9 while (!feof(fp)) 10 { 11 Data data; 12 int res = fscanf(fp,"%d %s %lf\n",&data.num,data.str,&data.dou); 13 cout<<"res == "<<res<<endl; 14 if(res == -1){ 15 break; 16 } 17 insert(head,&data); 18 } 19 fclose(fp); 20 return head; 21 }
2.2 fread()函數避免多讀取最后一行:
1 Node* readBit(){ 2 FILE* fp = NULL; 3 Node* head = NULL; 4 fp = fopen("fileBit.txt","r"); 5 if(fp == NULL){ 6 cout<<"Error(fopen):fp == NULL"<<endl; 7 return NULL; 8 } 9 while (!feof(fp)) 10 { 11 Data data; 12 int res = fread(&data,sizeof(Data),1,fp); 13 cout<<"res == "<<res<<endl; 14 if(res == 0){ 15 break; 16 } 17 insert(head,&data); 18 } 19 fclose(fp); 20 return head; 21 }
完整測試代碼:

1 #include<iostream> 2 #include<stdlib.h> 3 using namespace std; 4 5 typedef struct{ 6 int num; 7 char str[20]; 8 double dou; 9 }Data; 10 11 typedef struct node{ 12 Data data; 13 struct node* next; 14 }Node; 15 16 Data* input(); 17 void insert(Node*& head,Data* data); 18 void enterData(Node*& head); 19 void listData(Node* head,void visit(Data* item)); 20 void visit(Data* item); 21 void saveTxt(Node* head); 22 Node* readTxt(); 23 void saveBit(Node* head); 24 Node* readBit(); 25 26 Data* input(){ 27 Data* data = (Data*)calloc(1,sizeof(Data)); 28 cout<<"An Int:"; 29 cin>>data->num; 30 cout<<"a string:"; 31 cin>>data->str; 32 cout<<"a double:"; 33 cin>>data->dou; 34 return data; 35 } 36 37 void insert(Node*& head,Data* data){ 38 if(data == NULL){ 39 cout<<"Error:data == NULL\n"; 40 return; 41 } 42 if(head == NULL){ 43 head = (Node*)calloc(1,sizeof(Node)); 44 head->data = *data; 45 head->next = NULL; 46 }else{ 47 Node* node = (Node*)calloc(1,sizeof(Node)); 48 node->data = *data; 49 node->next = head->next; 50 head->next = node; 51 } 52 } 53 54 void enterData(Node*& head){ 55 char c; 56 do 57 { 58 Data* p = input(); 59 insert(head,p); 60 cout<<"continue?[y/n]:"; 61 cin>>c; 62 } while (c=='y'||c=='Y'); 63 } 64 65 void visit(Data* item){ 66 if(item == NULL){ 67 cout<<"Error(visit):item == NULL"<<endl; 68 } 69 cout<<"Int="<<item->num<<" str="<<item->str<<" double="<<item->dou<<endl; 70 } 71 void listData(Node* head,void visit(Data* item)){ 72 if(head == NULL){ 73 cout<<"Error(listData):head == NULL"<<endl; 74 } 75 Node* p = head; 76 while (p!=NULL) 77 { 78 visit(&(p->data)); 79 p = p->next; 80 } 81 } 82 83 void saveTxt(Node* head){ 84 int inres = 0; 85 FILE* fp = NULL; 86 if(head == NULL){ 87 cout<<"Error(saveTxt):head == NULL"<<endl; 88 return; 89 } 90 fp = fopen("file.txt","w"); 91 if(fp == NULL){ 92 cout<<"Error(fopen):fp == NULL"<<endl; 93 return; 94 } 95 Node* p = head; 96 while (p!=NULL) 97 { 98 inres = fprintf(fp,"%d %s %lf\n",p->data.num,p->data.str,p->data.dou); 99 cout<<"inres == "<<inres<<endl; 100 p = p->next; 101 } 102 fclose(fp); 103 } 104 105 Node* readTxt(){ 106 FILE* fp = NULL; 107 Node* head = NULL; 108 fp = fopen("file.txt","r"); 109 if(fp == NULL){ 110 cout<<"Error(fopen):fp == NULL"<<endl; 111 return NULL; 112 } 113 while (!feof(fp)) 114 { 115 Data data; 116 int res = fscanf(fp,"%d %s %lf\n",&data.num,data.str,&data.dou); 117 cout<<"res == "<<res<<endl; 118 if(res == -1){ 119 break; 120 } 121 insert(head,&data); 122 } 123 fclose(fp); 124 return head; 125 } 126 127 void saveBit(Node* head){ 128 FILE* fp = NULL; 129 if(head == NULL){ 130 cout<<"Error(saveBit):head == NULL"<<endl; 131 return; 132 } 133 fp = fopen("fileBit.txt","w"); 134 if(fp == NULL){ 135 cout<<"Error(fopen):fp == NULL"<<endl; 136 return; 137 } 138 Node* p = head; 139 while (p!=NULL) 140 { 141 fwrite(&(p->data),sizeof(Data),1,fp); 142 p = p->next; 143 } 144 fclose(fp); 145 } 146 147 Node* readBit(){ 148 FILE* fp = NULL; 149 Node* head = NULL; 150 fp = fopen("fileBit.txt","r"); 151 if(fp == NULL){ 152 cout<<"Error(fopen):fp == NULL"<<endl; 153 return NULL; 154 } 155 while (!feof(fp)) 156 { 157 Data data; 158 int res = fread(&data,sizeof(Data),1,fp); 159 cout<<"res == "<<res<<endl; 160 if(res == 0){ 161 break; 162 } 163 insert(head,&data); 164 } 165 fclose(fp); 166 return head; 167 } 168 169 int main(){ 170 Node* head = NULL,*headBit = NULL; 171 cout<<"sizeof(Data)=="<<sizeof(Data)<<endl; 172 //enterData(head); 173 //saveTxt(head); 174 head = readTxt(); 175 saveBit(head); 176 cout<<"bit---------------\n"; 177 headBit = readBit(); 178 listData(headBit,visit); 179 cout<<"txt---------------\n"; 180 listData(head,visit); 181 saveTxt(head); 182 return 0; 183 }