在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 }