C語言學習筆記(六)——文件操作

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

“`

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章