1.fopen函数
FILE *fopen(const char *path, const char *mode);
Fopen打开文件成功,返回有效FILE的有效地址,失败返回NULL
Path就是指定打开文件的路径,可以是相对路径,也可以是绝对路径,mode有以下几个值:
r 以只读方式打开文件,该文件必须存在,文件必须是可读的。
r+ 以可读写方式打开文件,该文件必须存在。
rb+ 读写打开一个二进制文件,允许读写数据,文件必须存在。
rw+ 读写打开一个文本文件,允许读和写。
w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留)
a+ 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 (原来的EOF符不保留)
只要成功用fopen打开的文件,使用完毕后一定要用fclose关闭。fclose的参数就是fopen的返回值
2.getc函数&putc函数
int getc(FILE *stream);
getc的参数是fopen成功打开文件后返回的指针,getc的返回值是一个char
getc的功能是以字节位单位读取文件内容
文本文件的最后结束标示是-1,也就是一个宏EOF
#define EOF -1
#include<stdio.h>
int main()
{
char a[]="/home/liu/1/a.tet";
FILE *p=fopen(a,"r");
if (p)
{
while(1)//循环输出文本的值
{
char c=getc(p);
if(c=EOF)
break;
print("%c",c);//此时输出a.txt的第一个字节
//char c=getc(p);//此时再输出会输出a.txt的第二个字节
fclose(p);
//char c=0
//while(c!=EOF)
//{c=getc(p);printf("%c");}//此时的问题在于会把-1输出。可以把printf和c=get(p)调整位置避免此问题
}
else
{
printf("fail\n");//这里不需要调用fclose
}
return 0;
}
下面看看putc函数吧
#include<stdio.h>
int main()
{
FILE *p=fopen("./a.txt","w");
if(p)
{
putc('a',p);
putc('\n',p);//向文件中写入一个字符
fclose(p);
}
return 0;
}
getc必须用r模式打开,putc必须用w模式打开。
int putc(int c, FILE *stream);第一个参数是要写入的char,第二个参数是fopen返回的文件指针
EOF与feof函数文件结尾
程序怎么才能知道是否已经到达文件结尾了呢?EOF代表文件结尾
如果已经是文件尾,feof函数返回true。
int feof(FILE *stream);,参数就是fopen返回的文件指针
EOF不属于文件的内容,只是文件的结尾标示,而且也不要直接用-1来代替EOF。
只有文本文件才能通过EOF判断文件的结尾标示,对于二进制文件EOF是无效的
通过getc,putc读写指定文件
#include<stdio.h>
int main(int argc,char **args)
{
if(argc<2)
return 0;
FILE *p=fopen(args[1],"w");
if(p)
{
while(1)
{
char c =getchar();//从标准输入设备读取一个字符
if(c=='0')
break;
putc(c,p);
}
fclose(p);
}
}
int main(int argc,char **args)
{
if (argc<2)
return 0;
FILE *p=fopen(args[1],"r");
if(p)
{
char c=getc(p);
while(c!=EOF)
{
printf("%c",c);
c=getc(p);
}
fclose(p);
}
return 0;
}
拷贝文件及加密解密的代码
#include<stdio.h>
int main(int argc,char **args)
//命令行有三个参数,第一个是源文件,第二个是目标文件,第三个0代表加密,1代表解密
{
if (argc<4)
return -1;
FILE *p=fopen(args[1],"r");
FILE *p1=fopen(args[2],"w");
if(p1==NULL)
return 0;
if(p)
{
char c=getc(p);
while(c!=EOF)
{
char tmp=args[3][0]
if (tmp=='0')
c++;
else
c--;
//c++;//从源文件中读一个char,然后修改了这个char的值,还原的方法就把c++改成c--,再把这个文件拷贝一次
putc(c,p1);//从p里面每读一个char,就往p1里面写一个char
c=getc(p);
}
}
fclose(p);
fclose(p1);
}
二进制和文本模式的区别
1.在windows系统中,文本模式下,文件以”\r\n”代表换行。若以文本模式打开文件,并用fputs等函数写入换行符”\n”时,函数会自动在”\n”前面加上”\r”。即实际写入文件的是”\r\n” 。
2.在类Unix/Linux系统中文本模式下,文件以”\n”代表换行。所以Linux系统中在文本模式和二进制模式下并无区别。
在windows读写文本文件的时候,是不写b,但读写二进制文件的时候一定要写b
Linux,b是忽略的。
14.6fprintf,fscanf,fgets,fputs函数
这些函数都是通过FILE *来对文件进行读写。
Fgets的返回值是char *,代表函数读到的字符串的首地址,如果fgets到了文件末尾,继续调用,返回NULL
#include<stdio.h>
int main(int argc,char **args)
{
if (argc<2)
return 0;
FILE *p=fopen(args[1],"w");
if(p)
{
while(1)
{
char buf[1024]={0};
fgets(buf,sizeof(buf),stdin);//读一行
if(strnhcmp(buf,"exit",4)==0)
break;
}
fclose(p);
}
return 0;
}
按行实现拷贝&加密
#include<stdio.h>
viod decode(char *s)
{
int len=0;
while(s[len])
{
s[len]++;
len++;
}
}
viod decode(char *s)
{
int len=0;
while(s[len])
{
s[len]--;
len++;
}
}
int main(int argc,char **args)
{
if (argc<4)
return 0;
FILE *p=fopen(args[1],"r");
if(p==NULL)
return 0;
FILE *p1=fopen(args[2],"w");
if(p==NULL)
return 0;
while(!foef(p))//只要没到文件结尾,那么循环就继续
{
char buf[1024]={0};
fgets(buf,sizeof(buf),p);//从源文件中读一行
if(args[3][0]=='0')
decode(buf);
else
encode(buf);
fputs(buf,p1);往目标文件写一行
//printf("%s",buf);//这里不带\n是因为文件中自带了换行
}
fclose(p);
fclose(p1);
return 0;
}
超大文件排序
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int main()
{
srand((unsigned int)time(NULL));
FILE *p=fopen("a.txt","w");
if(p)
{
int i;
for(i=0;i<10000000;i++)//就会产生一个很大的文件,那么如何对这个文件排序呢?排完还放回源文件
{
int seq=rand()%256;//文本文件是字符串,不能直接写进去,得到0-255之间的数
char buf[100]={0};
sprintf(buf,"%d\n",seq);//\n把每个生成的数分隔开
fputs(buf,p);
}
fclose(p);
}
return 0;
}
先排序100个吧
void bubble(int *a ,int n)
{
int i,j;
for(i=0;i<n;i++)
{
for(j=1;j<n-i;j++)
{
if(a[j-1]>a[j])
{
swap(&a[j-1],&a[j]);
}
}
}
}
void swap(int *a,int *b)
{int tmp=*a;*a=*b;*b=tmp;}
int main()
{
FILE *p=fopen("a.txt","r");
int array[100]={0};
int index=0;
while(!feof(p))
{
char buf[1024]={0};
fgets(buf,sizeof(buf),p);
array[index]=atoi(buf);// 把读出来的字符串转化为整数
index++;
}
fclose (p);
//此时需要给数组排序了
bubble(array,100);
FILE *p=fopen("a.txt","w");
int i;
for(i=0;i<100;i++)
{
char buf[1024]={0};
sprintf(buf,"%d\n",array[i]);//把数组转化为字符串
fputs(buf,p);
}
fclose(p);
return 0;
}
如果超大,冒泡不是很好用,此时需要其他的方法,先搭建一个框架
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int main01()
{
srand((unsigned int)time(NULL));
FILE *p=fopen("a.txt","w");
if(p)
{
int i;
for(i=0;i<10000000;i++)//就会产生一个很大的文件,那么如何对这个文件排序呢?排完还放回源文件
{
int seq=rand()%256;//文本文件是字符串,不能直接写进去,得到0-255之间的数
char buf[100]={0};
sprintf(buf,"%d\n",seq);//\n把每个生成的数分隔开
fputs(buf,p);
}
fclose(p);
}
return 0;
}
int main()
{
FILE *p=fopen("a.txt","r");
int array[256]={0};
while(!feof(p))
{
char buf[1024]={0};
fgets(buf,sizeof(buf),p);
int a=atoi(buf);
array[a]++;//这个的含义是统计某个数出现的次数
}
fclose(p);
p=fopen("a.txt","w");
int i,j;
for(i=0;i<256;i++)
{
for(j=0;j<array[i];j++)
{
char buf[100]={0};
sprintf(buf,"%d\n",i);
fputs(buf,p);
}
}
fclose(p);
}
a.txt中多少行不知道,每行的格式是固定的:
整数 运算符 整数 =
要求写个程序,运行的结果是在a.txt文件中每行后面添加运算结果(可以用堆、栈),但不能生成新的文件。
#include<stdio.h>
#include<stdlib.h>
int func1(int a,char b,int c)
{
swich(b)
{
case '+':
return a+c;
case '-':
return a-c;
case '*':
return a*c;
case '/':
if(c!=0)
return a/c
}
return 0;
}
#define NUM 100
int main()
{
FILE *p=fopen("a.txt","r");
//char array[100][100]={0};//只能处理100行那就用堆
char *array=calloc(NUM,sizeof(char));
int index=0;
char *tmp=array;//代表当前要写入字符的位置
//while(!feof(p))
while(1)
{
char buf[100]={0};
fgets(buf,sizeof(buf),p);//假设读到了最后一行,feof不会返回true,导致多输出了一个0
//已经到了最后一行,再次调用fgets,feof才返回true
if(feof(p))
break;
int a=0;
char b=0;
int c=0;
sscanf(buf,"%d%c%d=",&a,&b,&c);
//printf("%d%c%d=\n",a,b,c,func1(a,b,c));
sprintf(array,"%d%c%d=\n",a,b,c,func1(a,b,c));
array=relloc(array,NUM*(index+2));
tmp=array+(NUM*(index+1));//array永远指向堆内存的首地址,tmp每次往后移动100个字节。在array基础上加是为了防止中间过程中array的值变化。
index++;
}
fclose(p);
p=fopen("a.txt","w");
int i;
tmp=array;//让tmp回到起始位置
for(i=0;i<index;i++)
{
fputs(tmp,p)
tmp+=NUM;
}
fclose(p);
free(array);
return 0;
}
下面来看看fscanf和fprintf
#include<stdio.h>
int func1(int a,char b,int c)
{
swich(b)
{
case '+':
return a+c;
case '-':
return a-c;
case '*':
return a*c;
case '/':
if(c!=0)
return a/c
}
return 0;
}
int main()
{
FILE *p=fopen("a.txt","r")
FILE *p1=fopen("b.txt","w")
while(1)
{
int a=0;
char b=0;
int c=0;
fscanf(p,"%d%c%d",&a,&b,&c);//第一个参数是文件打开的指针,sscanf是从字符串读内容,fscanf是从文件中读字符串并转义
if(foef(p))
break;
//printf("%d,%c,%d\n",a,b,c);
fprintf(p1,"%d%c%d\n",a,b,c,func1(a,b,c));//printf是向标准输出设备输出sprintf是向字符串输出,fprintf是向文件输出
}
fclose(p);
fclose(p1);
return 0;
}
如果有个文本为
姓名= 刘X,年龄=50
姓名=王X,年龄=30
姓名=李X,年龄=20
解析这个文件
直接使用fscanf(p,”姓名=%s,年龄=%d”,name,&age);时会把姓名年龄都读到name中,age读不到东西,一直输出0。所以要先把字符串分开,再分别读取
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
FILE *p=fopen("a.txt","r");
while(1)
{
char buf[1024]={0};
fgets(buf,sizeof(buf),p);
if(feof(p))
break;
char *s=strtok(buf,",");//把字符串按照","分成两部分,然后存储前一部分(姓名部分)
char *name=strchr(s,'=');//找到'='号,此时直接输出是=刘X
printf("%s\n",&name[1]);
s=strtok(NULL,",");
//printf("%s\n",&s[7]);//年龄和=一共占了7个字节(UTF 8下)
printf("%d\n",atoi(&s[7]));//直接按整数解析出来
}
fclose(p);
return 0;
}
以上内容可以得到解析的姓名年龄,那么如何找到其中年龄第二大的成员呢?
首先来看如何在一个数组中找到第二大的值
int main()
{
int a[10]={32,65,12,5,8,23,245,86,22,91};
int max=0;
int smax=0;
int i;
for(i=0;i<10;i++)
{
if(a[i]>max)
{
smax=max;
max=a[i];
}
else if(a[i]<max&&a[i]>smax)
{
smax=a[i];
}
}
return 0;
}
```
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
FILE *p=fopen("a.txt","r");
int max=0;
int smax=0;
char max_name[100]={0};
char smax_name[100]={0};
while(1)
{
char buf[1024]={0};
fgets(buf,sizeof(buf),p);
if(feof(p))
break;
char *s=strtok(buf,",");//把字符串按照","分成两部分,然后存储前一部分(姓名部分)
char *name=strchr(s,'=');//找到'='号,此时直接输出是=刘X
//printf("%s\n",&name[1]);
s=strtok(NULL,",");
//printf("%s\n",&s[7]);//年龄和=一共占了7个字节(UTF 8下)
//printf("%d\n",atoi(&s[7]));//直接按整数解析出来
if(stoi(&s[7])>max)
{
smax=max;
max=stoi(&s[7]);
strcpy(smax_name,max_name);
strcpy(max_name,&name[1]);
}
else if(stoi(&s[7])<max&&stoi(&s[7])>smax)
{
smax=stoi(&s[7]);
strcpy(smax_name,&name[1]);
}
}
fclose(p);
return 0;
}
“`