Day16

2018-09-13  本文已影响0人  喝酸奶要舔盖__

文件操作

文件分类
文本文件是以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);
}

一次性写入多个字符
#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;
}

上一篇下一篇

猜你喜欢

热点阅读