• C语言基础 (12) 文件的操作 FILE


    1. 课程回顾

    结构体基本操作:

    1. 结构体类型的定义

    // struct为关键字 Stu为自定义标识符
    // struct Stu才是结构体类型

    // 结构体成员不能在定义类型时赋值

    struct Stu

    {

            int age;

            char name[50];

        int score;

    } // 后面有分号

    2。结构体的定义和初始化

    // 结构体变量初始化和数组很类似,只有在定义时,才能初始化

    // 定义结构体变量时,别忘了struct关键字

    struct Stu obj = {18,”mike”,58}

    3。结构体成员变量的使用

    obj.age = 18;

    (&obj)->age = 18;

    2.结构体指针变量

    1)       指针变量指向栈区

    struct Stu *p = NULL;

    struct Stu obj; //栈区结构体

    p = &obj; //指向栈区

    p ->age = 18;

    (*p).age = 18;

       2) 指针变量指向堆区

              struct Stu *p = NULL;

              // 指向堆区

              p = (struct Stu *)malloc(sizeof(struct Stu));

              p -> age = 18;

              free(p);

             p = NULL;

    3const修饰的指针变量

    //看const修饰是*还是变量

    const struct Stu *p (代表指针所指向的内存不能变

    struct Stu const *p;(代表指针不能变

    3.结构体数组

    stuct Stu obj[3] = {

      {18,”lily”,03},

      {18,”lily”,03},

      {18,”lily”,03},

    }

    struct Stu obj2[3] = {18,”lily”,99,22,”lucy”,-80,33….} // 这样就比较不清晰了

    struct Stu tmp[3]

    int I = 0

    for (I = 0;i<3;i++)

    {

       (tmp +i)->age = 18+I;

    (*(tmp+i)).age = 18+I; // .的优先级高,所以要加括号

    tmp[i].age = 18+I; //常用

    }

    4.结构体和函数

    1)  同类型结构体变量赋值

    struct Stu obj1 = {18,”lily”,99};

    struct Stu obj2;

    • obj2 = obj1;

    2)函数值传递

    a)

    struct Stu p;

    // 结构体变量本身传递(值传递),形参修改不会影响到实参

    // 调用完毕fun()函数,p的成员还是没有赋值

    fun(p)

    void fun(struct stu p) //值传递,相当于拷贝了一份,所以并没有变

    {

      p.age = 18;

      strcpy(p.name,”mike”);

      p.score = 59;

    }

    3 函数地址传递

      struct Stu p;

      fun(&p);

      void fun(struct Stu *p)

      {

    p->age = 18;

    strcpy(p->name,”mike”);

    p->score = 59;

    }

    5 结构体套一级指针

      struct stu

      {

    int age;

    char *name; // 一级指针

    int score;

    }; // 后面有分号

    1)  栈区结构体

    struct Stu s;

    s.age =10;

    s.name = (char *)malloc( strlen(“mike”) +1);

    strcpy(s.name,”mike”);

    s.score = 59;

    free(s.name);

    2堆区结构体

    struct Stu *p; //结构体是指针,后面在堆区分配空间

    p = (struct Stu *)malloc(sizeof(struct Stu))

    p->name = (char *)malloc(strlen(“mike”)+1)

    p->age = 18

    strcpy(p->name,”mike”)

    p->score = 59

    free(p->name)

    free(p)

    枚举

    typedef

    #define INT int

    宏定义是在预处理阶段,前面的替换后面的

    typedef是在编译阶段,后面的替换前面的

    2 作业讲解

    3 文件概述

    printf 把内存中的10先放到缓冲区,再放到屏幕

    为什么不直接打印到屏幕,而放到缓冲区呢?

    为了效率,就是缓存 (可能会拿很多次,

    如果只拿一次,当然是直接给屏幕比较快,但是可能会拿很多次

    FILE 所有平台的名字都一样,FILE是一个结构体类型,里面的成员功能一样,不同平台成员的名字不一样

    FILE *fp

    看一下stdio.h

    为了兼容改成typedef 最后转成FILE

    不同平台成员不一样

    (vs2013 vs2015同一个平台不同编译器,里面成员都不一样

    FILE所有平台的名字都一样,FILE是一个结构体类型,里面的成员功能一样,不同平台成员的名字不一样

    FILE *fp

    1、fp指针,只用调用了fopen(),在堆区分配空间,把地址返回给fp

    2、fp指针不是指向文件,fp指针和文件关联,fp内部成员保存了文件的状态

    char *p

    *fp(不能这样写!!不是里面是文件,fp只是保存了文件的状态

    fd 文件描述符

    ulimit

    1,2被占用了 从3开始

     

    3、操作fp指针 不能直接操作,必须通过文件库函数来操作fp指针

    4、通过库函数操作fp指针,对文件的任何操作,fp内部成员会有相应的变化(操作系统自动完成)

    结论:文件的操作是需要操作系统层来支持的,通过文件库函数来操作,不是像普通指针一样,p,*p这样直接拿内容。

    https://stackoverflow.com/questions/5130375/how-exactly-does-fopen-fclose-work

    https://www.cnblogs.com/llguanli/p/6791507.html

    4 文件分类

    分为设备文件和磁盘文件

    5 文件操作流程

    1、  打开文件fopen()

    2、  读写文件

    a) 按字符读写fgetc(),fputc()

    b) 按字符串(行)读取文件fgets(),fputs()

    c) 文件结尾判断 feof()          // end of file

    3、  关闭文件flose()

    6 标准文件设备指针

     fp指向堆区一片空间,空间中的数据和硬盘种的关联了

    文件指针

    stdin,stdout,stderr

    7 标准设备补充

    8 文件的打开关闭

    FILE *fp = NULL;

    //1、windows路径写法 因为是转义字符,所以需要\

    fl = fopen(“D:\1.txt”,”w”); //windows

    fp = fopen(“D:/1.txt”,”w”); //linux,windows

    // 当前路径

    fp = fopen(“a.txt”,”w”)

    fp = fopen(“./a.txt,”w”)

    //绝对路径

    fp = fopen(“/home/edu/a.txt”,”w”);

    fopen会在堆区分配空间,返回堆区地址给fp

    9 文件路径说明

    相对路径:

    1、在linux,相对路径相对于可执行程序

    2、VS

       a,编译同时运行程序,相对路径是相对于.vcxproj(项目文件)所在的路径

       b, 如果直接运行程序,相对路径线相对于可执行程序

    3、Qt

       a, 编译同时运行程序,相对路径,相对于debug所在的路径

       b, 如果直接运行程序,相对路径相对于可执行程序

    fopen(“1.txt”,”w”);

    char *p = “1.txt”; //指向文字常量区

    fopen(p,”w”);

    char p[] = “1.txt” //栈区/数组

    fopen(p,”w”); //数组名字是首元素地址

    char *mode = “w”;

    fopen(“1.txt”,mode);

    10 上午知识复习

    1.文件的类型

    文本文件和二进制文件

    2.文件的打开关闭

    1.文件指针

      FILE *fp;

       stdin  //0 标准输入

       stdout //1 标准输出

       stderr //2 标准出错

    2.文件的打开

      fopen(‘路径’,’权限w/r/a’)

    3.文件的关闭

    11 fputc的使用

    1 打开文件fopen()

    2 读写文件

    3 关闭文件f close

     

    12 fputc的使用补充

     

    13 fgetc的使用

    1、如果是文本文件,可以通过-1(EOF) 判断文件是否结尾

       (!ASCII码没有-1

    #include <stdio.h>

    #include <string.h>

     

    void write_file()

    {

        //1、打开文件

        FILE *fp = fopen("4.txt", "w");

     

        if (fp == NULL)

        {

            perror("write_file fopen");

            return;

        }

     

        //2、写文件

        char *p = "abcdef";

        int i = 0;

        int n = strlen(p);

        for (i = 0; i < n; i++)

        {

            fputc(p[i], fp);

        }

     

        //3、关闭文件

        fclose(fp);

    }

     

    void read_file()

    {

        //1、打开文件 以读的方式打开

        FILE *fp = fopen("4.txt", "r");

     

        if (fp == NULL)

        {

            perror("write_file fopen");

            return;

        }

     

        //2、读文件,每次读一个字符

        char ch;

        // while (ch != -1) //EOF 文本文件结尾默认是-1

        while (ch != EOF) // 有这个宏

        {

            ch = fgetc(fp);

            // printf("ch = %c ", ch); //以char形式打出

            printf("ch = %d ", ch);  //以数字形式打出

        }

     

        //3、关闭文件

        fclose(fp);

    }

     

    int main(int argc, char const *argv[])

    {

     

        write_file();

        read_file();

        return 0;

    }

    14 feof的存在意义

    1、如果是文本文件,可以通过-1(EOF)判断文件是否结尾

    2、如果是二进制文件,不能以-1判断文件结尾

    3、feof()判断文件是否结尾,任何文件都能判断

    15 feof的使用

    feof(fp) // 如果到文件结尾,返回真

    1、如果第一次没有对文件进行读操作,直接调用此函数,永远返回真

    2、此函数必须,先读,再调用feof() 才有意义

    3、调用此函数,光标不会自动往后移动

    4、必须读取后,才能判断是否结束,判断的是读取的字符

    (这个东西是判断光标以前的字符

    16 feof的使用补充

    17 cat命令的实现

    将mycat放在cat所在路径

    放到目录里 然后用mycat命令就可以了,C语言的cat命令就是这样实现的

    18 课堂答疑

    19 vi命令的实现

    不能用scanf 因为不能有回车 空格

    gets 不能有回车

    所以只能用fgets (可以有空格,也可以有回车

    // 读一点写一点

    20 课堂答疑

    注意 fgets会保存’ ’

    21 fputs的使用

    22 fgets的使用

    读一下,发现后面全都是mike

    因为读到文件结尾的时候会接触本次读取,所以buf内的内容并没有变,还是最后一行的内容,

    用一下memset:

    (边界值的问题,现在也顺便讲解了memset怎么用的

    循环读取:

    解决方法:

    (放前面

    23 作业

  • 相关阅读:
    String 方法
    异常处理
    数组长度改变方法
    对象
    重载(函数)
    函数
    java基础(死循环退出选项)
    cookie的封装,获取,删除
    事件监听的理解
    JS少数兼容
  • 原文地址:https://www.cnblogs.com/eret9616/p/10247038.html
Copyright © 2020-2023  润新知