4.C语言文件操作
总论
1.fopen
r以只读方式打开文件,该文件必须存在
r+以可读写方式打开文件,文件必须存在
rb+读写打开一个二进制文件,允许读写数据,文件必须存在
rw+读写打开一个文本文件,允许读和写
w 打开只写文件,若文件存在则文件长度清零,即该文件内容会消失,若文件不存在则建立该文件
w+打开可读文件,若文件存在则文件长度清为零,即该文件内容会消失,若文件不存在则建立该文件
a 以附加的方式打开只写文件.若文件不存在,则会建立该文件,如果存在,数据会被加到文件尾,即文件原先的内容会被保留(EOF符不保留)
a+以附加的方式打开可读写的文件.若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留.(原来的EOF符不保留)
- 1.文件基础操作
1.1 打开文件示例
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 3 int main() 4 { 5 FILE *p = fopen("a.txt","w");//用写的方式打开一个文件 6 fputs("hello",p);//向文件写入一个字符串 7 fclose(p);//关闭这个文件 8 printf("Hello World!\n"); 9 return 0; 10 }
执行完再执行一遍的时候,文件内容消失,是新的内容
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include<string.h>; 3 4 int main() 5 { 6 char s[1024] = {0}; 7 FILE *p = fopen("a.txt","w");//用写的方式打开一个文件 8 while(1) 9 { 10 memset(s,0,sizeof(s)); 11 //scanf("%s",s); 12 gets(s); 13 if(strcmp(s,"exit")==0) 14 break; 15 int len = strlen(s); 16 s[len] = '\n'; 17 fputs(s,p); 18 } 19 printf("Hello World!\n"); 20 return 0; 21 }
1.2.读文件示例
用fgets函数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int main() 2 { 3 char s[1024] = {0}; 4 FILE *p = fopen("a.txt","r");//用读方式打开文件 5 //feof(p);//如果已经到了文件最后,函数返回真 6 while(!feof(p)) 7 { 8 memset(s,0,sizeof(s)); 9 fgets(s,sizeof(s),p);//第一个参数是一个内存地址;第二个参数是这块内存的大小; 10 //第三个参数是fopen返回的指针 11 //每次读一行 12 printf("%s",s); 13 } 14 15 fclose(p); 16 return 0; 17 }
1.3.文件加密
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 void code(char *s) 2 { 3 while(*s)//遍历一个字符串 4 { 5 (*s)++; 6 s++; 7 } 8 } 9 10 void decode(char *s) 11 { 12 while(*s) 13 { 14 (*s)--; 15 s++; 16 } 17 } 18 19 int main1()//加密 20 { 21 char s[1024] = {0}; 22 FILE *p = fopen("a.txt","r");//用读方式打开文件 23 FILE *p1 = fopen("b.txt","w");//用写的方式打开一个文件 24 //feof(p);//如果已经到了文件最后,函数返回真 25 while(!feof(p)) 26 { 27 memset(s,0,sizeof(s)); 28 fgets(s,sizeof(s),p);//第一个参数是一个内存地址;第二个参数是这块内存的大小; 29 //第三个参数是fopen返回的指针 30 //每次读一行 31 code(s); 32 fputs(s,p1); 33 } 34 35 fclose(p); 36 fclose(p1); 37 return 0; 38 } 39 40 int main()//解密 41 { 42 char s[1024] = {0}; 43 FILE *p = fopen("b.txt","r");//用读方式打开文件 44 FILE *p1 = fopen("c.txt","w");//用写的方式打开一个文件 45 //feof(p);//如果已经到了文件最后,函数返回真 46 while(!feof(p)) 47 { 48 memset(s,0,sizeof(s)); 49 fgets(s,sizeof(s),p);//第一个参数是一个内存地址;第二个参数是这块内存的大小; 50 //第三个参数是fopen返回的指针 51 //每次读一行 52 decode(s); 53 fputs(s,p1); 54 } 55 56 fclose(p); 57 fclose(p1); 58 return 0; 59 }
1.4.文本文件排序(使用冒泡排序)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 void swap(int *a,int *b)//交换参数的值 2 { 3 int tmp = *a; 4 *a = *b; 5 *b = tmp; 6 } 7 8 void pupple(int *p,int n)//冒泡排序 9 { 10 int i; 11 int j; 12 for(i=0;i<n;i++) 13 { 14 for(j=0;j<n-i;j++) 15 { 16 if(p[j-1]>p[j]) 17 { 18 swap(&p[j-1],&p[j]); 19 } 20 } 21 } 22 } 23 24 int main() 25 { 26 int index = 0; //这是个计数器 27 int array[100] = {0}; 28 29 char buf[100]; 30 31 FILE *p = fopen("1.txt","r"); 32 if(p==NULL) 33 { 34 printf("error\n"); 35 } 36 else 37 { 38 39 while(!feof(p))//如果没有到达文件结尾,那么循环继续 40 { 41 memset(buf,0,sizeof(buf));//每次去文件之前都把这个buffer清空 42 fgets(buf,sizeof(buf),p);//从文件中读取一行 43 array[index] = atoi(buf);//将读取的一行转化为int,赋值给数组成员 44 index++; 45 } 46 47 fclose(p); 48 } 49 50 pupple(array,index);//将数组排序 51 52 p = fopen("2.txt","w");//用写的方式打开2.txt 53 int i=0; 54 for(i=0;i<index;i++) 55 { 56 memset(buf,0,sizeof(buf));//每次操作之前都把buf清空 57 sprintf(buf,"%d\n",array[i]);//将数组的成员转化为字符串 58 fputs(buf,p); 59 } 60 61 fclose(p); 62 63 return 0; 64 }
但是这样做的缺点是在栈中分配内存,很容易造成栈溢出,所以我们对main函数进行改进,动态分配数组
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int main()//在堆中建立一个数组 2 { 3 int index = 0; //这是个计数器 4 5 FILE *p = fopen("1.txt","r");//第一次打开a.txt目的是要知道这个文件有多少行 6 while(!feof(p))//如果没有到达文件结尾,那么循环继续 7 { 8 index++; 9 } 10 fclose(p); 11 12 int *array = calloc(sizeof(int),index);//在堆中建立一个动态数组 13 14 char buf[100]; 15 p = fopen("1.txt","r"); 16 index = 0;//计数器重新从0开始 17 if(p==NULL) 18 { 19 printf("error\n"); 20 } 21 else 22 { 23 24 while(!feof(p))//如果没有到达文件结尾,那么循环继续 25 { 26 memset(buf,0,sizeof(buf));//每次去文件之前都把这个buffer清空 27 fgets(buf,sizeof(buf),p);//从文件中读取一行 28 array[index] = atoi(buf);//将读取的一行转化为int,赋值给数组成员 29 index++; 30 } 31 32 fclose(p); 33 } 34 35 pupple(array,index);//将数组排序 36 37 p = fopen("2.txt","w");//用写的方式打开2.txt 38 int i=0; 39 for(i=0;i<index;i++) 40 { 41 memset(buf,0,sizeof(buf));//每次操作之前都把buf清空 42 sprintf(buf,"%d\n",array[i]);//将数组的成员转化为字符串 43 fputs(buf,p); 44 } 45 46 fclose(p); 47 48 return 0; 49 }
1.5.解析文本内容,计算文本中的加减乘除
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <string.h> 3 4 int calc_string(const char *s) 5 { 6 char buf1[100] = {0}; 7 char oper1 = 0; 8 char buf2[100] = {0}; 9 10 int len = strlen(s); 11 int i; 12 for(i=0;i<len;i++) 13 { 14 if(s[i]=='+' || s[i]=='-' ||s[i]=='*' ||s[i]=='/') 15 { 16 strncpy(buf1,s,i); 17 oper1 = s[i]; 18 break; 19 } 20 } 21 22 int start=i+1; 23 for(;i<len;i++) 24 { 25 if(s[i]=='=') 26 { 27 strncpy(buf2,&s[start],i-start); 28 } 29 } 30 31 switch(oper1) 32 { 33 case '+': 34 return atoi(buf1) + atoi(buf2); 35 case '-': 36 return atoi(buf1) - atoi(buf2); 37 case '*': 38 return atoi(buf1) * atoi(buf2); 39 case '/': 40 { 41 int a=atoi(buf2); 42 if(a) 43 return atoi(buf1)/atoi(buf2); 44 else 45 return 0; 46 } 47 48 } 49 } 50 51 void cutereturn(char *s)//去掉最后最后的回车符 52 { 53 int len = strlen(s); 54 if(s[len-1]=='\n') 55 s[len-1]=0; 56 } 57 58 int main() 59 { 60 FILE *p = fopen("calc.txt","r"); 61 FILE *p1 = fopen("res.txt","w"); 62 char buf[1024]; 63 char buf1[1024]; 64 65 if(p) 66 { 67 while (!feof(p)) 68 { 69 memset(buf,0,sizeof(buf)); 70 fgets(buf,sizeof(buf),p);//从文件中读取一行记录,字符串最后是一'\'结尾 71 cutereturn(buf); 72 73 int value = calc_string(buf); 74 memset(buf1,0,sizeof(buf1)); 75 sprintf(buf1,"%s%d\n",buf,value); 76 fputs(buf1,p1); 77 } 78 } 79 80 return 0; 81 }
1.6 fscanf与fprintf的用法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int main1()//fsancf 2 { 3 FILE *p = fopen("calc.txt","r"); 4 while(!feof(p)) 5 { 6 char buf[100] = {0}; 7 //fgets(buf,sizeof(buf),p); 8 //fscanf(p,"%s",buf);//fscanf与scanf用法基本一致,fscanf是从一个文本读取输入,scanf是从键盘读取输入 9 int a; 10 int b; 11 fscanf(p,"%d+%d",&a,&b); 12 printf("a=%d,b=%d",a,b); 13 } 14 } 15 16 void main()//fprintf 17 { 18 FILE *p =fopen("1.txt","w"); 19 20 char buf[100]="hello world"; 21 int a = 6; 22 int b = 7; 23 fprintf(p,"%s,%d,%d",buf,a,b);//和printf功能一样,fprintf将输入到文件里面 24 fclose(p); 25 return 0 ; 26 }
- 二进制文本操作
2.1 二进制读取和文本读取的区别
对于传统的windows下的文件是以/r/n作为文件换行,如果是用fgets()或用fputs()函数,会做一个自动的转换,把/r/n转换成/n,写入的时候又转换成/r/n,而如果采用二进制读取的话用fread,不会做转化,/r/n会分开读取.fread不会按照一行一行来操作,而是按照一个整体来操作
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 void main(void) 2 { 3 FILE *p = fopen("calc.txt","rb");//用读二进制的文件的方式打开一个文件 4 char buf[1024]={0}; 5 fread(buf,sizeof(char),sizeof(buf),p);//第一个参数是缓冲区,第二个参数是读取的时候最小单位大小, 6 //第三个参数是一次读取多少个单位,第四个是文件指针 7 8 printf("%s\n",buf); 9 return 0; 10 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int main() 2 { 3 FILE *p = fopen("1.txt","wb"); 4 char buf[1024]={0}; 5 buf[0]='a'; 6 buf[1]='b'; 7 buf[2]='\r'; 8 buf[3]='\n'; 9 buf[4]='c'; 10 fwrite(buf,sizeof(char),5,p); 11 fclose(p); 12 }
2.2二进制文件拷贝
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int main() 2 { 3 FILE *p = fopen("a.wmv","rb"); 4 FILE *p1 = fopen("2.wmv","wb"); 5 char buf[1024*4]; 6 while(!feof(p)) 7 { 8 memset(buf,0,sizeof(buf)); 9 size_t res = fread(buf,sizeof(char),sizeof(buf),p);//返回从源文件中读取的字节数 10 fwrite(buf,sizeof(char),res,p1);//从源文件读取多少字节,就往源文件中写入多少字节 11 } 12 fclose(p); 13 fclose(p1); 14 return 0; 15 }
2.3二进制文件加密
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
- 三.文件中常用操作
3.1 在堆中分配内存拷贝文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int main() 2 { 3 struct stat st= {0};//定义一个结构,名字叫st 4 stat("1.txt",&st);//调用完stat函数中之后,文件相关信息就保存在st结构中了 5 char *array=malloc(st.st_size);//根据文件大小在堆中动态的分配一块内存 6 FILE *p = fopen("a.wmv","rb"); 7 fread(array,sizeof(char),st.st_size,p);//相当于一下把整个文件放入内存 8 p=fopen("test.wmv","wb"); 9 fwrite(array,sizeof(char),st.st_size,p);//将堆中的信息一下都写入文件 10 return 0; 11 }
3.2结构体与二进制文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 struct student 2 { 3 char name[100]; 4 int age; 5 }; 6 7 int main1() 8 { 9 struct student st = {"池国维",22}; 10 FILE *p=fopen("stu.dat","wb"); 11 fwrite(&st,sizeof(st),1,p); 12 fclose(p); 13 return 0; 14 } 15 16 int main() 17 { 18 struct student st = {0}; 19 FILE *p=fopen("stu.dat","rb"); 20 fread(&st,sizeof(st),1,p); 21 fclose(p); 22 printf("name=%s,age=%d\n",st.name,st.age); 23 return 0; 24 }
3.3大文件数据排序
核心思想就是以一个新的数组的下标表示数据中相应的数出现的次数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int main() 2 { 3 4 FILE *p = fopen("big.txt","r"); 5 int array[513]={0}; 6 while(!feof(p)) 7 { 8 char buf[100]={0}; 9 fgets(buf,sizeof(buf),p); 10 if(buf[0] != 0)//如果读取的行不是空行,那么久执行代码 11 { 12 int value = atoi(buf);//将得到的行转化为int 13 array[value]++; 14 } 15 16 } 17 fclose(p); 18 19 p = fopen("res.txt","w"); 20 int i; 21 int j; 22 for(i=0;i<513;i++) 23 { 24 for(j=0;j<array[i];j++) 25 { 26 fprintf(p,"%d\n",i); 27 } 28 } 29 fclose(p); 30 printf("end"); 31 32 return 0; 33 }
3.4文件位置操作-fseek与ftell
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 struct student 2 { 3 char name[10]; 4 int age; 5 }; 6 7 int main1()//写文件 8 { 9 struct student st[10] = {0}; 10 11 int i; 12 for(i=0;i<10;i++) 13 { 14 printf("please input name:"); 15 scanf("%s",st[i].name); 16 printf("please input age:"); 17 scanf("%d",&st[i].age); 18 } 19 20 FILE *p = fopen("student.dat","wb"); 21 fwrite(st,sizeof(struct student),10,p); 22 fclose(p); 23 } 24 25 int main()//读文件 26 { 27 struct student st = {0}; 28 FILE *p = fopen("student.dat","rb"); 29 // while(!feof(p)) 30 // { 31 // memset(&st,0,sizeof(struct student)); 32 // if(fread(&st,sizeof(struct student),1,p) == 0)//fread只能往前走,不能往后退 33 // break; 34 // printf("name=%s,age=%d\n",st.name,st.age); 35 // } 36 //那么如何才能在指定位置读取呢,就需要用到fseek函数 37 38 //fseek(p,sizeof(struct student),SEEK_SET);//从文件开始位置向后偏移结构student这么多的字节 39 memset(&st,0,sizeof(struct student)); 40 fread(&st,sizeof(struct student),1,p); 41 printf("name=%s,age=%d\n",st.name,st.age); 42 fseek(p,0-sizeof(struct student),SEEK_CUR);//从当前位置往回偏移 43 memset(&st,0,sizeof(struct student)); 44 fread(&st,sizeof(struct student),1,p); 45 printf("name=%s,age=%d\n",st.name,st.age); 46 47 printf("ftell = %d\n",ftell(p));//当前文件指针p在第7个字节 48 49 fclose(p); 50 return 0; 51 }
3.5 fflush
fflush(p)将缓冲区的内容立刻写入文件,优势是不会因为停电,或者电脑死机等故障导致缓冲区内容丢失,不好的是硬盘读写次数增加,导致程序效率低下,同时硬盘寿命会变短,修改配置文件的时候,有时候会用,或者做一些不经常修改的数据,但很重要的数据,那么用fflush.
3.6 文件删除和改名
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int main()//文件删除和改名 2 { 3 remove("2.wmv"); 4 remove("3.wmv"); 5 remove("a.wmv"); 6 rename("1.txt","111.txt"); 7 }