学习一门语言,学会文件操作是十分必要的,如果没有学会文件操作,从某种角度上来说,就基本很难体现出这种语言的价值。C语言库函数为文件操作提供了丰富的库函数,接下来我们需要做的是学会使用这些库函数,在我看来学会这些库函数已经学会文件操作的一大半了,接下来我会根据自己的理解来解析一些常用的文件操作函数。

fopen函数

FILE *fopen(const char *path,const char *mode)//文件指针名=fopen(文件名,使用文件方式)

     功能:打开一个文件,打开成功返回有效的文件地址,失败则返回NULL。

     path表示文件路径

     mode选择文件的打开方式:

    r      以只读的方式打开文件

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

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

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

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

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

FILE *p =fopen(“E://1.txt”,”r”);
if(p){
printf(“success\n”);
}

     只要fopen成功打开文件,使用完后一定要调用fclose关闭。fclose的参数就是fopen的返回值。

     int fclose(FILE *p);

getc函数

     int getc(FILE *stream);

    getc的参数是fopen成功打开文件后返回的指针,getc的返回值是一个char,功能是以字节为单位读取文件内容。

    文本文件最后的结束标识符是-1,也就是宏EOF,EOF不是文件的一部分内容,只是文件结束的标识。二进制文件的结束标识符则不一定是-1。

putc函数

     int putc(char c,FILE *stream);

     c是需要写入文件的字符,stream是fopen成功打开文件后返回的指针,功能是向文件写入一个指定的字符。

     getc必须用r模式打开,putc必须用w模式打开,读和写一定要分清模式。

     下面例子会展示通过getc和putc读写指定文件

//使用putc例程
int main(int argc, char **args){
    FILE *p = fopen(args[1], "w+");
    if (argc<2) return 0;
    if(p){             //指定写文件
        while(1)
        {
            char c = getchar();
            if (c == '\n')
                break;
            putc(c, p);
        }
        fclose(p);
    }
    return 0;
}
//使用getc例程
int main(int argc, char **args){
    FILE *p = fopen(args[1], "r");
    if (argc<2) return 0;
    if (p){             //指定读文件
        char c = getc(p);
        while(c != EOF){
            printf("%c", c);
            c = getc(p);
        }
        getchar();
        fclose(p);
    }
    return 0;
}

fgets函数与fputs函数

int fputs(const char *str, FILE *stream);

      返回值:该函数返回一个非负值,如果发生错误则返回 EOF(-1)。str:这是一个数组,包含了要写入的以空字符终止的字符序列。stream:指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流

char *fgets(char *buf, int bufsize, FILE *stream);
      *buf: 字符型指针,指向用来存储所得数据的地址。
      bufsize: 整型数据,指明存储数据的大小。
      *stream: 文件结构体指针,将要读取的文件流

       fgets从stream中读取数据,每次读取一行。读取的数据保存在buf指向的字符数组中,每次最多读取bufsize-1个字符(第bufsize个字符赋'\0'),如果文件中的该行,不足bufsize-1个字符,则读完该行就结束。如若该行(包括最后一个换行符)的字符数超过bufsize-1,则fgets只返回一个不完整的行,但是,缓冲区总是以NULL字符结尾,对fgets的下一次调用会继续读该行。函数成功将返回buf,失败或读到文件结尾返回NULL。

       fputs向指定的文件写入一个字符串(不自动写入字符串结束标记符‘\0’)。成功写入一个字符串后,文件的位置指针会自动后移,函数返回值为非负整数;否则返回EOF(符号常量,其值为-1)。

int main(){
    FILE *p = fopen("x.txt", "w");
    FILE *p1 = fopen("1.txt", "r");
    if (p){
    while (!feof(p1)){  //只要没到文件结尾那么循环继续
            char buf[1024] = { 0 };
            fgets(buf, sizeof(buf), p1);
            //fgets(buf, sizeof(buf), stdin);
            if (!strncmp(buf, "exit", 4))//若str1与str2的前n个字符相同,则返回0;若s1大于s2,则返回大于0的值;若s1 小于s2,则返回小于0的值。
                break;
            fputs(buf, p);
        }
        fclose(p);
        fclose(p1);
    }
    return 0;
}

 EOF与feof函数文件结尾

int feof(FILE *stream);

      如果已经是文件结尾,feof函数返回true;EOF不属于文件内容,知识文件的结尾标识,而且也不要用-1直接代替EOF。只有文本文件才能通过EOF判断文件的结尾标识,对二进制文件EOF是无效的

fgets与fputs实现文件加密解密

#include<stdlib.h>
#include<string.h>
#include<stdio.h>
FILE *f_mp4, *P1;
void decode(char* s)
{
    int len = 0;
    while (s[len])
    {
        s[len]++;
        len++;
    }
}
void encode(char* s)
{
    int len = 0;
    while (s[len])
    {
        s[len]--;
        len--;
    }
}
int main(int argc, char **args)  //通过命令行指定拷贝文件
{
    if (argc<4) return -1;
    f_mp4 = fopen(args[1], "r");
    if (f_mp4 == NULL)return 0;
    P1 = fopen(args[2], "w");
    if (P1 == NULL)return 0;
    while (!feof(f_mp4))
    {
        char buf[1024] = { 0 };
        fgets(buf, sizeof(buf), f_mp4);
        if (args[3][0] == '0')//如果成立则加密
            encode(buf);
        else if (args[3][0] == '1')//如果成立就解密
            decode(buf);
        fputs(buf, P1);
    }
    fclose(f_mp4);
    fclose(P1);
}

超大文件排序

     有时候会对超大文件进行排序,我们的方法是先把超大文件读取到数组里,然后在再使排序算法对其进行排序,在写入到文件里。

int main()
{
    srand((unsigned int)time(NULL));
    FILE *p = fopen("a.txt", "w");
    if (p)
    {
        for (int i = 0; i < 1000; i++)
        {
            int seq = rand();
            char buf[100] = { 0 };
            sprintf(buf,"%d\n", seq);
            fputs(buf, p);
        }
        fclose(p);
    }
    FILE *p1 = fopen("a.txt","r");
    int arry[100] = { 0 };
    int index = 0;
    while (!feof(p1))
    {
        char buf[1024] = { 0 };
        fgets(buf, sizeof(buf), p1);
        arry[index] = atoi(buf);//把读出来的字符串转化为数组
        index++;
    }
    bubble(arry, index); //排序算法,此处需要自己写排序算法
    fclose(p1);
}

fprintf与fscanf函数

        fprintf格式化输出到一个流/文件中;函数原型为int fprintf( FILE *stream, const char *format, [ argument ]...),fprintf()函数根据指定的格式(format)向输出流(stream)写入数据(argument)。

       fscanf函数原型为 int fscanf(FILE * stream, const char * format, [argument...]); 其功能为根据数据格式(format)从输入流(stream)中读入数据(存储到argument);与fgets的差别在于:fscanf遇到空格和换行时结束,注意空格时也结束,fgets遇到空格不结束。

//1.txt文件内容
//2+3=
//56+90=
int main(){
    FILE *P = fopen("1.txt","r");
    FILE *P1 = fopen("2.txt", "w");
    while (!feof(P))
    {
        int a = 0;
        char b = 0;
        int c = 0;
        fscanf(P,"%d%c%d=", &a, &b, &c);//fscanf是从一个文件中读取字符串,并转义
        if (feof(P)) break;
        fprintf(P1, "%d%c%d=%d\n", a, b, c, (a + c));//fprintf和sprintf功能类似,只是目标是文件,而不是字符串
    }
    fclose(P);
    fclose(P1);
}
//本例子主要是读取文件里的年龄
/*************txt文件内容*****************
年龄=15
年龄=89
年龄=23
****************************************/
int main(){
    FILE *p = fopen("1.txt", "r");
    while (!feof(p))
    {
        int age = 0;
        char buf[100];
        fgets(buf, sizeof(buf), p);
        sscanf(buf, "年龄=%d", &age);//sscanf是从一个字符串中读取字符串,并转义
        printf("%d\n", age);
    }
    getchar();
    fclose(p);
}