总论


1.fopen

  r以只读方式打开文件,该文件必须存在

  r+以可读写方式打开文件,文件必须存在

  rb+读写打开一个二进制文件,允许读写数据,文件必须存在

  rw+读写打开一个文本文件,允许读和写

  w 打开只写文件,若文件存在则文件长度清零,即该文件内容会消失,若文件不存在则建立该文件

  w+打开可读文件,若文件存在则文件长度清为零,即该文件内容会消失,若文件不存在则建立该文件

  a 以附加的方式打开只写文件.若文件不存在,则会建立该文件,如果存在,数据会被加到文件尾,即文件原先的内容会被保留(EOF符不保留)

  a+以附加的方式打开可读写的文件.若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留.(原来的EOF符不保留)


  • 1.文件基础操作

1.1 打开文件示例

 #include <stdio.h>

 int main()
{
FILE *p = fopen("a.txt","w");//用写的方式打开一个文件
fputs("hello",p);//向文件写入一个字符串
fclose(p);//关闭这个文件
printf("Hello World!\n");
return ;
}

QT w方式打开文件

执行完再执行一遍的时候,文件内容消失,是新的内容

 #include <stdio.h>
#include<string.h>; int main()
{
char s[] = {};
FILE *p = fopen("a.txt","w");//用写的方式打开一个文件
while()
{
memset(s,,sizeof(s));
//scanf("%s",s);
gets(s);
if(strcmp(s,"exit")==)
break;
int len = strlen(s);
s[len] = '\n';
fputs(s,p);
}
printf("Hello World!\n");
return ;
}

一个写文件实例


1.2.读文件示例

用fgets函数

 int main()
{
char s[] = {};
FILE *p = fopen("a.txt","r");//用读方式打开文件
//feof(p);//如果已经到了文件最后,函数返回真
while(!feof(p))
{
memset(s,,sizeof(s));
fgets(s,sizeof(s),p);//第一个参数是一个内存地址;第二个参数是这块内存的大小;
//第三个参数是fopen返回的指针
//每次读一行
printf("%s",s);
} fclose(p);
return ;
}

读函数实例


1.3.文件加密

 void code(char *s)
{
while(*s)//遍历一个字符串
{
(*s)++;
s++;
}
} void decode(char *s)
{
while(*s)
{
(*s)--;
s++;
}
} int main1()//加密
{
char s[] = {};
FILE *p = fopen("a.txt","r");//用读方式打开文件
FILE *p1 = fopen("b.txt","w");//用写的方式打开一个文件
//feof(p);//如果已经到了文件最后,函数返回真
while(!feof(p))
{
memset(s,,sizeof(s));
fgets(s,sizeof(s),p);//第一个参数是一个内存地址;第二个参数是这块内存的大小;
//第三个参数是fopen返回的指针
//每次读一行
code(s);
fputs(s,p1);
} fclose(p);
fclose(p1);
return ;
} int main()//解密
{
char s[] = {};
FILE *p = fopen("b.txt","r");//用读方式打开文件
FILE *p1 = fopen("c.txt","w");//用写的方式打开一个文件
//feof(p);//如果已经到了文件最后,函数返回真
while(!feof(p))
{
memset(s,,sizeof(s));
fgets(s,sizeof(s),p);//第一个参数是一个内存地址;第二个参数是这块内存的大小;
//第三个参数是fopen返回的指针
//每次读一行
decode(s);
fputs(s,p1);
} fclose(p);
fclose(p1);
return ;
}

简单文件加密解密


1.4.文本文件排序(使用冒泡排序)

 void swap(int *a,int *b)//交换参数的值
{
int tmp = *a;
*a = *b;
*b = tmp;
} void pupple(int *p,int n)//冒泡排序
{
int i;
int j;
for(i=;i<n;i++)
{
for(j=;j<n-i;j++)
{
if(p[j-]>p[j])
{
swap(&p[j-],&p[j]);
}
}
}
} int main()
{
int index = ; //这是个计数器
int array[] = {}; char buf[]; FILE *p = fopen("1.txt","r");
if(p==NULL)
{
printf("error\n");
}
else
{ while(!feof(p))//如果没有到达文件结尾,那么循环继续
{
memset(buf,,sizeof(buf));//每次去文件之前都把这个buffer清空
fgets(buf,sizeof(buf),p);//从文件中读取一行
array[index] = atoi(buf);//将读取的一行转化为int,赋值给数组成员
index++;
} fclose(p);
} pupple(array,index);//将数组排序 p = fopen("2.txt","w");//用写的方式打开2.txt
int i=;
for(i=;i<index;i++)
{
memset(buf,,sizeof(buf));//每次操作之前都把buf清空
sprintf(buf,"%d\n",array[i]);//将数组的成员转化为字符串
fputs(buf,p);
} fclose(p); return ;
}

文本文件排序

但是这样做的缺点是在栈中分配内存,很容易造成栈溢出,所以我们对main函数进行改进,动态分配数组

 int main()//在堆中建立一个数组
{
int index = ; //这是个计数器 FILE *p = fopen("1.txt","r");//第一次打开a.txt目的是要知道这个文件有多少行
while(!feof(p))//如果没有到达文件结尾,那么循环继续
{
index++;
}
fclose(p); int *array = calloc(sizeof(int),index);//在堆中建立一个动态数组 char buf[];
p = fopen("1.txt","r");
index = ;//计数器重新从0开始
if(p==NULL)
{
printf("error\n");
}
else
{ while(!feof(p))//如果没有到达文件结尾,那么循环继续
{
memset(buf,,sizeof(buf));//每次去文件之前都把这个buffer清空
fgets(buf,sizeof(buf),p);//从文件中读取一行
array[index] = atoi(buf);//将读取的一行转化为int,赋值给数组成员
index++;
} fclose(p);
} pupple(array,index);//将数组排序 p = fopen("2.txt","w");//用写的方式打开2.txt
int i=;
for(i=;i<index;i++)
{
memset(buf,,sizeof(buf));//每次操作之前都把buf清空
sprintf(buf,"%d\n",array[i]);//将数组的成员转化为字符串
fputs(buf,p);
} fclose(p); return ;
}

main函数改进,动态分配内存


1.5.解析文本内容,计算文本中的加减乘除

 #include <stdio.h>
#include <string.h> int calc_string(const char *s)
{
char buf1[] = {};
char oper1 = ;
char buf2[] = {}; int len = strlen(s);
int i;
for(i=;i<len;i++)
{
if(s[i]=='+' || s[i]=='-' ||s[i]=='*' ||s[i]=='/')
{
strncpy(buf1,s,i);
oper1 = s[i];
break;
}
} int start=i+;
for(;i<len;i++)
{
if(s[i]=='=')
{
strncpy(buf2,&s[start],i-start);
}
} switch(oper1)
{
case '+':
return atoi(buf1) + atoi(buf2);
case '-':
return atoi(buf1) - atoi(buf2);
case '*':
return atoi(buf1) * atoi(buf2);
case '/':
{
int a=atoi(buf2);
if(a)
return atoi(buf1)/atoi(buf2);
else
return ;
} }
} void cutereturn(char *s)//去掉最后最后的回车符
{
int len = strlen(s);
if(s[len-]=='\n')
s[len-]=;
} int main()
{
FILE *p = fopen("calc.txt","r");
FILE *p1 = fopen("res.txt","w");
char buf[];
char buf1[]; if(p)
{
while (!feof(p))
{
memset(buf,,sizeof(buf));
fgets(buf,sizeof(buf),p);//从文件中读取一行记录,字符串最后是一'\'结尾
cutereturn(buf); int value = calc_string(buf);
memset(buf1,,sizeof(buf1));
sprintf(buf1,"%s%d\n",buf,value);
fputs(buf1,p1);
}
} return ;
}

1.6 fscanf与fprintf的用法

 int main1()//fsancf
{
FILE *p = fopen("calc.txt","r");
while(!feof(p))
{
char buf[] = {};
//fgets(buf,sizeof(buf),p);
//fscanf(p,"%s",buf);//fscanf与scanf用法基本一致,fscanf是从一个文本读取输入,scanf是从键盘读取输入
int a;
int b;
fscanf(p,"%d+%d",&a,&b);
printf("a=%d,b=%d",a,b);
}
} void main()//fprintf
{
FILE *p =fopen("1.txt","w"); char buf[]="hello world";
int a = ;
int b = ;
fprintf(p,"%s,%d,%d",buf,a,b);//和printf功能一样,fprintf将输入到文件里面
fclose(p);
return ;
}

fscanf与fprintf

  • 二进制文本操作

2.1 二进制读取和文本读取的区别

对于传统的windows下的文件是以/r/n作为文件换行,如果是用fgets()或用fputs()函数,会做一个自动的转换,把/r/n转换成/n,写入的时候又转换成/r/n,而如果采用二进制读取的话用fread,不会做转化,/r/n会分开读取.fread不会按照一行一行来操作,而是按照一个整体来操作

 void main(void)
{
FILE *p = fopen("calc.txt","rb");//用读二进制的文件的方式打开一个文件
char buf[]={};
fread(buf,sizeof(char),sizeof(buf),p);//第一个参数是缓冲区,第二个参数是读取的时候最小单位大小,
//第三个参数是一次读取多少个单位,第四个是文件指针 printf("%s\n",buf);
return ;
}

fread

 int main()
{
FILE *p = fopen("1.txt","wb");
char buf[]={};
buf[]='a';
buf[]='b';
buf[]='\r';
buf[]='\n';
buf[]='c';
fwrite(buf,sizeof(char),,p);
fclose(p);
}

fwrite

2.2二进制文件拷贝

 int main()
{
FILE *p = fopen("a.wmv","rb");
FILE *p1 = fopen("2.wmv","wb");
char buf[*];
while(!feof(p))
{
memset(buf,,sizeof(buf));
size_t res = fread(buf,sizeof(char),sizeof(buf),p);//返回从源文件中读取的字节数
fwrite(buf,sizeof(char),res,p1);//从源文件读取多少字节,就往源文件中写入多少字节
}
fclose(p);
fclose(p1);
return ;
}

fread fwrite

2.3二进制文件加密

Code
  • 三.文件中常用操作

3.1 在堆中分配内存拷贝文件

 int main()
{
struct stat st= {};//定义一个结构,名字叫st
stat("1.txt",&st);//调用完stat函数中之后,文件相关信息就保存在st结构中了
char *array=malloc(st.st_size);//根据文件大小在堆中动态的分配一块内存
FILE *p = fopen("a.wmv","rb");
fread(array,sizeof(char),st.st_size,p);//相当于一下把整个文件放入内存
p=fopen("test.wmv","wb");
fwrite(array,sizeof(char),st.st_size,p);//将堆中的信息一下都写入文件
return ;
}

3.2结构体与二进制文件

 struct student
{
char name[];
int age;
}; int main1()
{
struct student st = {"池国维",};
FILE *p=fopen("stu.dat","wb");
fwrite(&st,sizeof(st),,p);
fclose(p);
return ;
} int main()
{
struct student st = {};
FILE *p=fopen("stu.dat","rb");
fread(&st,sizeof(st),,p);
fclose(p);
printf("name=%s,age=%d\n",st.name,st.age);
return ;
}

3.3大文件数据排序

核心思想就是以一个新的数组的下标表示数据中相应的数出现的次数

 int main()
{ FILE *p = fopen("big.txt","r");
int array[]={};
while(!feof(p))
{
char buf[]={};
fgets(buf,sizeof(buf),p);
if(buf[] != )//如果读取的行不是空行,那么久执行代码
{
int value = atoi(buf);//将得到的行转化为int
array[value]++;
} }
fclose(p); p = fopen("res.txt","w");
int i;
int j;
for(i=;i<;i++)
{
for(j=;j<array[i];j++)
{
fprintf(p,"%d\n",i);
}
}
fclose(p);
printf("end"); return ;
}

3.4文件位置操作-fseek与ftell

 struct student
{
char name[];
int age;
}; int main1()//写文件
{
struct student st[] = {}; int i;
for(i=;i<;i++)
{
printf("please input name:");
scanf("%s",st[i].name);
printf("please input age:");
scanf("%d",&st[i].age);
} FILE *p = fopen("student.dat","wb");
fwrite(st,sizeof(struct student),,p);
fclose(p);
} int main()//读文件
{
struct student st = {};
FILE *p = fopen("student.dat","rb");
// while(!feof(p))
// {
// memset(&st,0,sizeof(struct student));
// if(fread(&st,sizeof(struct student),1,p) == 0)//fread只能往前走,不能往后退
// break;
// printf("name=%s,age=%d\n",st.name,st.age);
// }
//那么如何才能在指定位置读取呢,就需要用到fseek函数 //fseek(p,sizeof(struct student),SEEK_SET);//从文件开始位置向后偏移结构student这么多的字节
memset(&st,,sizeof(struct student));
fread(&st,sizeof(struct student),,p);
printf("name=%s,age=%d\n",st.name,st.age);
fseek(p,-sizeof(struct student),SEEK_CUR);//从当前位置往回偏移
memset(&st,,sizeof(struct student));
fread(&st,sizeof(struct student),,p);
printf("name=%s,age=%d\n",st.name,st.age); printf("ftell = %d\n",ftell(p));//当前文件指针p在第7个字节 fclose(p);
return ;
}

3.5 fflush

fflush(p)将缓冲区的内容立刻写入文件,优势是不会因为停电,或者电脑死机等故障导致缓冲区内容丢失,不好的是硬盘读写次数增加,导致程序效率低下,同时硬盘寿命会变短,修改配置文件的时候,有时候会用,或者做一些不经常修改的数据,但很重要的数据,那么用fflush.

3.6 文件删除和改名

 int main()//文件删除和改名
{
remove("2.wmv");
remove("3.wmv");
remove("a.wmv");
rename("1.txt","111.txt");
}

最新文章

  1. canvas孙悟空脚踩白云今年是猴年
  2. Jmeter中察看结果树中的响应数据,中文显示乱码问题处理
  3. xib与nib的区别
  4. MySQL数据库百万级高并发网站实战
  5. 对中级Linux用户有用的20个命令
  6. eclipse安装pydev插件
  7. 2014-9-17二班----9 web project
  8. IOC框架Ninject实践总结
  9. Oracle + Entity Framework 更新没有设置主键的表
  10. hibernate_validator_03
  11. java组装json和提取一个json的例子
  12. Android的JunitTest
  13. (转)个例子让你了解Java反射机制
  14. 201621123031 《Java程序设计》第11周学习总结
  15. SmartSql Config配置
  16. 【调试基础】Part 4 保护模式
  17. flink1.7 checkpoint源码分析
  18. SAP配置BOM的适用范围
  19. CodeFroces-- 514.div2.C-Sequence Transformation
  20. Github+HEXO FATAL bad indentation of a mapping entry at line 84

热门文章

  1. [Chromium]怎样安全的使用PostTask
  2. [Angular] Handle HTTP Errors in Angular with HttpErrorResponse interface
  3. UVA 1329 Corporative Network【并查集】
  4. Qt 3D教程(三)实现对模型材质參数的控制
  5. bzoj1797: [Ahoi2009]Mincut 最小割(最小割+强联通tarjan)
  6. hdoj--1010--Tempter of the Bone(搜索+奇偶剪枝)
  7. SPOJ 694/705 后缀数组
  8. vue keep-alive保存路由状态2 (高级用法,接上篇)
  9. hiho160周 - 字符串压缩,经典dp
  10. swift中高阶函数map、flatMap、filter、reduce