Day16

作者: 喝酸奶要舔盖__ | 来源:发表于2018-09-13 13:54 被阅读0次

    文件操作

    文件分类
    • 文本文件
    文本文件是以ASCII码存储的
    
    • 二进制文件
    二进制文件是以二进制存储的
    
    • 两者区别
      注意点: 任何文本编辑器在打开文件的时候,都会以某种编码方式取解码存储的数据,而文本编辑器默认的解码方式就是ASCII解码
    1.存储步骤不同: 
       文本文件在存储的时候,会先查询需要存储数据的ASCII码,然后再将对应的ASCII码转换为二进制,然后再存储
       二进制文件在存储的时候,会直接转换为二进制存储
    2.从存储步骤来看,文本文件需要先查找再存储,所以效率会低一些
    3.从内存上来看,文本文件更占内存
    
    文件的打开和关闭

    重点: 文件打开模式重点记住w+和a+模式,而且在读写操作时候,文件打开的模式在windows平台要以wb+,rb+这种方式书写

    #include <stdio.h>
    
    int main()
    {
        /*
         * 文件的打开和关闭
         * 1. 文件打开函数 fopen(const char * filename,const char * mode)
         *   第一个参数: 需要打开文件的名称
         *   第二个参数: 打开文件的模式
         *   返回值: 如果打开文件成功,会返回文件的句柄
         *
         *
         * 2.文件关闭函数 用来关闭先前fopen()打开的文件
         *   fclose(想要关闭的文件); 
         *   返回值: 成功返回0, 失败返回EOF(-1)
         */
    
        //文件打开函数模式
        //1. r模式,读取文件
        // 文件不存储会报错,文件存储就打开, 只能读不能写
        FILE *fp = fopen("lnj.txt","r");
        
        //2. w模式,写入文件
        // 文件不存储会自动创建,会将存储的文件直接打开, 只能写不能读
    
        //3. r+模式,读取和写入文件
        // 文件不存储会报错,文件存在就打开, 既可以读也可以写
        
        //4. w+模式,读取和写入文件(重点)
        // 文件不存储会自动创建,文件存在就直接打开, 既可以读也可以写
        
        //5. a模式,追加写入文件
        // 文件不存储会自动创建,文件存在就直接打开, 只能写不能读
        
        //6. a+模式,追加写入文件,并且可以读取(重点)
        // 文件不存储会自动创建,文件存在就直接打开, 可以在原有的数据的基础上追加,并且还可以读取数据
        
        //关闭文件
        fclose(fp);
        return 0;
        
    }
    
    FILE 结构体
         fopen函数返回的是FILE *是一个指向结构体的指针
         FILE * 并不是打开的那个文件,而是一个结构体,这个结构体中描述了被打开文件在缓冲区中的各种状态
        
         FILE结构体
         struct _iobuf {
                char *_ptr;  //文件输入的下一个位置
                int _cnt;  //当前缓冲区的相对位置
                char *_base; //文件的起始位置)
                int _flag; //文件标志
                int _file;  //文件的有效性验证
                int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取
                int _bufsiz; // 缓冲区大小
                char *_tmpfname; //临时文件名
              };
              typedef struct _iobuf FILE;
    

    文本文件

    一次写入和读取一个字符
    • 写入
    #include <stdio.h>
    
    int main()
    {
        /*
         * 一次写入一个字符
         * fputc这个函数就是一次写入一个字符,fputc是以文本文件的形式保存数据
         * 第一个参数: 需要写入到文件的字符
         * 第二个参数: 已经打开的文件句柄
         * 返回值: 写入成功,返回写入成功字符,如果失败,返回EOF(-1)本质就是-1
         * 注意点: w/w+ 如果文件中有内容会覆盖之前的内容
         */
    
        //1. 先打开一个文件
        FILE *fp = fopen("it.txt", "w");
        //2. 往文件中写入一个字符
        int res = fputc('a', fp);
        printf("%i\n", res);
        //3. 关闭打开的文件
        fclose(fp);
        return 0;
    }
    
    
    • 读取
    #include <stdio.h>
    
    int main()
    {
        /*
         * 一次读取一个字符
         * fgetc()函数
         * 第一个参数: 被读取的文件的句柄
         * 返回值: 当前读取到的字符,如果失败就返回EOF
         * 注意点:fputc函数每次写入一个字符,指针就会往后面移动一位
         *        fgetc函数每次读取后,指针就会往后移动一位
         */
        FILE *fp = fopen("it.txt", "w+");
        fputc('a',fp);
        fputc('b',fp);
        fputc('c',fp);
    
        // 将头文件指针重新指向一个流的开头
        rewind(fp);
    
    //    char ch = fgetc(fp);
    //    printf("ch = %c\n",ch);
        
        char ch;
        while((ch = fgetc(fp)) != EOF){
            printf("ch = %c\n",ch);
        }
        return 0;
    }
    
    
    • 简单的加密解密练习
    #include <stdio.h>
    
    void encode(char *name, char *newName,int code);
    int main()
    {
        /*
         * 简单的文件加密和解密
         * 思想: 利用异或一个数组两次会得到它本身
         */
        encode("it.txt","itencode", 5);
        encode("itencode","itdecode", 5);
        return 0;
    }
    void encode(char *name, char *newName,int code){
        //1. 打开一个需要加密的文件
        FILE *fr = fopen(name,"r+");
        //2. 打开一个需要写入的加密内容的文件
        FILE *fw = fopen(newName,"w+");
        //3. 不断的读不断的加密文件写入
        char ch = EOF;
        while ((ch = fgetc(fr)) != EOF) {
            ch = ch ^ code;
            fputc(ch, fw);
        }
        //4. 关闭已经打开的文件
        fclose(fr);
        fclose(fw);
    }
    
    
    一次性写入多个字符
    • 写入
      fputs函数是以文本文件形式存储,存储的是ASCII
      如果利用fputs函数写入字符遇到\0会终止写入
    #include <stdio.h>
    
    int main()
    {
        /*
         * 一次性写入一行数据
         * fputs函数可以一次写入一堆字符
         * 第一个参数: 需要写入的数据
         * 第二个参数: 写入到的文件的句柄
         * 注意点: 不会在写入字符的后面自动添加\n
                  写入的时候遇到\0会停止写入
         */
    
        //1. 打开一个文件
        FILE *fp = fopen("test.txt", "w+");
        fputs("helloworld\n",fp);
        fputs("helloworld\n",fp);
    
        //关闭打开的文件
        fclose(fp);
        return 0;
    }
    
    • 读取
    #include <stdio.h>
    
    int main()
    {
        /*
         * 一次性读取一行数据
         * fgets()函数是一次读取一行数据
         * 第一个参数: 读取出来的数据会放到这个参数的变量中
         * 第二个参数: 需要读取多少个字符的数据
         * 第三个参数: 被读取文件的句柄
         *
         * 注意点: 
         * 1.虽然告诉系统需要读取1024个字符,但是只要遇到\n,fgets()函数会自动终止读取
         * 2. 每次只能读取n-1个字符,读取完成会在末尾自动添加\0
         * 3. 遇到EOF也会自动停止读取
         */
        //打开一个文件
        FILE *fp = fopen("test.txt", "r+");
        // 定义一个字符数组保存读取的内容
        char buf[1024];
        fgets(buf, 1024, fp);
        return 0;
    }
    
    • 读取多行内容
    #include <stdio.h>
    
    int main()
    {
        /*
         * 使用fgets一次读取多行内容
         * 返回值: char * 正常返回字符指针,出错或遇到文件结尾返回空指针NULL
         */
    
        FILE *fp = fopen("test.txt", "r+");
        char buf[1024];
        //一次读取多行内容
        while ((fgets(buf, 1024, fp)) != NULL) {
            printf("%s", buf);
        }
        return 0;
    }
    

    二进制文件读写操作

    普通数据读写

    • 写入
    #include <stdio.h>
    
    int main()
    {
        /*
         * 用于操作二进制文本的读写函数
         * fwrite / fread这两个函数就是用于操作二进制文本的
         *
         * fwrite函数 一次性写入一块数据
         * 第一个参数: 需要写入文件的数据地址
         * 第二个参数: 每次写入多少个字节
         * 第三个参数: 需要写入多少次
         * 第四个参数: 被写入文件的句柄
           返回值: 写入多少次就返回多少,如果出错或者文件结束就返回0
         * 
         * 注意点: 在二进制当中,是没有\0 \n这些转义字符的概念,写入的受到这些字符的影响
                  一般写入数据,每次写入多少个字节写大点,写入次数写少点
         */
    
        FILE *fp = fopen("abc.txt", "w+");
        int age[] = {1,3,5};
        //将age中sizeof(age)个字节一次性写入到对应的fp文件当中
        fwrite(&age, sizeof(age), 1, fp);
    
        return 0;
    }
    
    • 读取
    #include <stdio.h>
    
    int main()
    {
    #include <stdio.h>
    
    int main()
    {
        /*
         * 一次性读取一块内容
         * fread()函数
         * 第一个参数: 读取的数据存储到哪
         * 第二个参数: 一次读取多少个字节
         * 第三个参数: 一共读取多少次
         * 第四个参数: 被读取文件的句柄
         * 返回值: 读取多少次就返回多少,如果出错就返回0
         *
         * 注意: 虽然告诉系统需要读取1024次,但是只要读取到EOF就不会再读取了
         *      一般情况下读取一块数据,每次都按照读取数据类型来接收,一共读取多少次按照字节数来填写
         * 
         */
        FILE *fp = fopen("def.txt", "r+");
        char buf[1024] = {0};
        fread(buf, 1, 1024, fp);
        printf("buf = %s\n", buf);
        return 0;
    }
    
    
    结构体读写操作
    • 读写普通结构体
    #include <stdio.h>
    //定义一个结构体
    typedef struct person
    {
        char name[8];
        int age;
        double height;
    } Person;
    
    
    int main()
    {
        /*
         * 二进制读写对结构体操作
         */
    
        //1. 往文件中写入一个结构体
        Person p = {"wjh", 18, 1.7};
        FILE *fp = fopen("per.txt", "wb+");
        fwrite(&p, sizeof(Person), 1, fp);
        fclose(fp);
    
        //2. 读取一个文件中的结构体
        Person p;
        FILE *fp = fopen("per.txt", "rb+");
        fread(&p, sizeof(p), 1, fp);
        printf("name = %s\n", p.name);
        printf("age = %i\n", p.age);
        printf("height = %lf\n", p.height);
        fclose(fp);
        return 0;
    }
    
    • 读写结构体数组
    #include <stdio.h>
    //定义一个结构体
    typedef struct person
    {
        char name[8];
        int age;
        double height;
    } Person;
    
    int main()
    {
        /*
         * 读写结构体数组
         */
    
    //    Person ps[3] = {
    //        {"lnj", 20, 1.7},
    //        {"wjh", 18, 1.8},
    //        {"niuzi", 17, 1.6},
    //    };
    
        //1.往文件中写入结构体数组
    //    FILE *fp = fopen("ps.txt", "wb+");
    //    fwrite(&ps, sizeof(ps), 1, fp);
    //    fclose(fp);
    
        //2. 读取文件中结构体数组
        FILE *fp = fopen("ps.txt", "rb+");
        Person ps[3];
        fread(&ps, sizeof(Person), 3, fp);
        for(int i = 0; i < 3; i++){
            Person p  = ps[i];
            printf("name = %s\n", p.name);
            printf("age = %i\n", p.age);
            printf("height = %lf\n", p.height);
        }
        return 0;
    }
    

    链表读写

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    typedef struct person
    {
        char name[8];
        int age;
        double height;
        struct person *next;
    } Person;
    Person* createEmpty();
    void insertNode(Person *head, Person per);
    void printList(Person *head);
    void saveList(Person *head);
    Person *loadList(char *name);
    int main()
    {
        /*
         * 二进制读写对链表操作
         */
    
        //1. 创建一个空链表
        Person *head = createEmpty();
        //2. 往空链表中插入数据
        insertNode(head, (Person){"lnj", 19, 1.8});
        insertNode(head, (Person){"wjh", 13, 1.6});
        insertNode(head, (Person){"niuzi", 20, 1.5});
        //3. 增删改查操作
    //    printList(head);
        //4.将链表保存到文件中
    //    saveList(head);
        //5. 从文件中读取链表
        loadList()
        //6. 增删改查操作
        return 0;
    }
    Person *loadList(char *name){
        //1. 创建一个空链表
        Person *head = createEmpty();
        //2. 打开文件
        FILE *fp = fopen(name, "rb+");
        //3. 创建一个节点
        Person p;
        while (fread(&p, sizeof(Person), 1, fp) > 0) {
            insertNode(head, p);
        }
    }
    
    /**
     * @brief printList 遍历链表
     * @param head 链表的头指针
     */
    void printList(Person *head){
        // 头节点对我们来说没有用,头节点没有保存数据
       //1. 取出头节点的下一个节点
        Person *cur = head->next;
        //2. 判断是否为NULL,如果不为NULL就开始遍历
        while(cur != NULL){
            //2.1 取出当前数据打印
            printf("name = %s\n", cur->name);
            printf("age = %i\n", cur->age);
            printf("height = %lf\n", cur->height);
            //2.2 让当前节点往后移动
            cur = cur->next;
        }
    }
    /**
     * @brief saveList 将有效节点写入到文件
     * @param head  链表的头指针
     */
    
    void saveList(Person *head, char *name){
        //1. 打开文件
        FILE *fp = fopen(name, "wb+");
        //2. 定义指针变量保存头节点的下一个节点
        Person *cur = head->next;
        while (cur != NULL){
            //写入一个有效的节点
            fwrite(cur, sizeof(Person), 1, fp);
            // 让指针往后移动
            cur = cur->next;
        }
        //3. 关闭文件
        fclose(fp);
    }
    
    
    /**
     * @brief insertNode 封装一个插入新节点的函数
     * @param head 头节点
     * @param num  插入新节点的数据
     */
    void insertNode(Person *head, Person data){
        //1. 创建一个新节点
        Person *node  = (Person *)malloc(sizeof(Person));
        //2. 将数据保存到新节点中
        for(int i = 0; i < strlen(data.name); i++){
            node->name[i] = data.name[i];
        }
        node->age = data.age;
        node->height = data.height;
        //3. 插入节点
        //3.1 将新节点的下一个节点 等于 头节点的下一个节点
        node->next = head->next;
        //3.2 让头节点的下一个节点 等于 新节点
        head->next = node;
    }
    
    /**创建空链表的函数
     * @brief createList
     * @return
     */
    Person* createEmpty(){
        //1. 定义头指针
        Person *head  = NULL;
        // 空链表只有头指针和一个节点,并且节点没有数据,也有没有下一个节点
        //2. 创建一个空节点,并赋值给头指针
        head = (Person *)malloc(sizeof(Person));
        head->next = NULL;
        //3.返回头指针
        return head;
    }
    
    

    相关文章

      网友评论

          本文标题:Day16

          本文链接:https://www.haomeiwen.com/subject/uonigftx.html