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;
}
“`