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

“`

猜你喜欢

转载自blog.csdn.net/qq_21747841/article/details/78273841