• C语言文件操作


    C语言文件操作

    什么是文件

    文件就是在磁盘上的一段存储空间

    不同文件的格式是不一样的,也就是说文件存储的数据是不同的。比如 txt(文本文件) 存储的是字符数据,png(图片文件) 存储的是颜色标识数据,exe(可执行文件) 存储的都是代码。当然数据的本质都是二进制的 0和1,不同的文件在宏观上都是使用 后缀 来区分的。

    所谓文件操作,就是把文件内容读进程序里,然后根据格式进行解析,进行读写等操作。


    如何操作文件

    一、打开文件

    FILE *fopen( const char *filepath,  const char *mode );
    
    • 1

    使用上面这个函数来打开一个文件。它的原理是在物理内存开辟一块空间,将磁盘中被选定文件的内容复制过来(本质就是一大堆字符串),然后进行操作。当我们操作文件结束之后,再把复制的这一份更新到磁盘空间,最终完成修改。

    FILE*                 //返回值是一个文件指针,也就是物理内存上这块空间的首地址
    fopen                 //函数名
    const char *filepath  //参数1,文件的路径(绝对、相对路径),注意绝对路径的\要进行转义
    const char *mode      //参数2,文件的打开方式
    
    • 1
    • 2
    • 3
    • 4

    当我们对文件的操作结束后,需要在程序中关闭文件。这一步会将我们修改后的文件更新到磁盘空间,把开辟的操作文件内存空间释放。

    int fclose( FILE *stream ); //唯一参数,文件指针
    
    • 1

    二、文件的打开方式

    (一)文本模式(默认的打开模式)

    1. r模式:只读模式

      r模式,又称 rt (read text) 模式,通过这种形式打开文件,文件就只能读取,不能修改。且打开的前提要求是文件必须存在,不存在则打开失败,会报错。

    2. w模式:可读可写模式之从头来过

      w模式,又称 wt 模式,通过 w 模式打开的文件,首先会自动擦除原数据。比如文件原来有内容,w 模式打开就会先把文件擦除,重新按照操作写入新数据。

      而当文件不存在的时候,会创建文件

    3. a模式:可读可写模式之狗尾续貂

      a模式,又称 at 模式(append),通过 a 模式打开的文件,不会擦除原有数据,而是在原有内容后面接着写。比如文件有内容,打开文件内容原封不动,如果写入新内容,就会在原有的尾巴上接着写。

      文件不存在的时候,会创建文件

    4. 三种模式的plus版本

      r+模式( r模式plus版本 ),通过这个模式打开文件,可读可写。所以plus之处就是加上了“写”操作。注意前提仍然是文件必须存在。而且 r+ 模式等同 w 模式,都是擦除写。

      同理,w+ 和 a+ 模式就是 w 和 a 模式的plus版本。因为plus之处在于加上“写”操作,所以plus版本和以前没什么变化。

    (二)二进制模式(需要指定的模式)

    1. rb模式:只读模式

      rb(read bit)模式,原理同 rt 模式。(文件必须存在)

    2. wb模式:可读可写模式之从头来过

      wb模式,原理同 wt 模式。(文件不存在会创建文件)

    3. ab模式:可读可写模式之狗尾续貂

      ab模式,原理同 ab 模式。(文件不存在会创建文件)

    4. 三种模式的plus版本

      rb+模式( rb 模式plus版本 ),文件可读可写。注意前提仍然是文件必须存在。而且 r+ 模式等同 w 模式,都是擦除写。

      同理,wb+ 和 ab+ 模式没什么变化。


    三、操作文件

    (一)写

    1. fwrite:一次写入指定字节数

      size_t fwrite(         //返回值是实际写入的字符数(int型),写入失败会返回 0
         const void *buffer, //参数1:要写入文件的数据的首地址,可以是字符串、数组、结构体
         size_t size,        //参数2:sizeof(类型)
         size_t count,       //参数3:数据数量,参数2与参数3相乘得出写入的字节数
         FILE *stream        //参数4:文件指针
      );
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      举个栗子:

      #include <stdio.h>
      #include <string.h>
      
      int main()
      {
          char* str = "I LOVE YOU !";
      
          FILE* f = fopen("C:\\Users\\13040\\Desktop\\test.txt", "w");
      
          fwrite(str, sizeof(char), strlen(str), f);
          fwrite("\n", sizeof(char), 1, f);  // 写入回车
          fwrite(str, sizeof(char), strlen(str), f);
      
          fclose(f);
      
          return 0;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
    2. fputs:一次写入一行(但它不会自动加换行,换行需要自己在输入字符串尾巴加\n)

      int fputs( const char *str,   FILE *stream );
      
      //返回值:成功返回 0,失败返回EOF(-1)
      //参数1:输入的字符串(只能输入字符串)
      //参数2:文件指针
      
      • 1
      • 2
      • 3
      • 4
      • 5

      举个李子:

      #include <stdio.h>
      #include <string.h>
      
      int main()
      {
          char* str = "I LOVE YOU !";
      
          FILE* f = fopen("C:\\Users\\13040\\Desktop\\test.txt", "w");
      
          fputs(str, f);
          fputs("\n", f);
          fputs(str, f);
      
          fclose(f);
      
          return 0;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
    3. fprintf:格式化写入

      int fprintf( 
         FILE *stream,        //文件指针
         const char *format [,//和printf函数一样的参数要求
            argument ]...
      );
      
      • 1
      • 2
      • 3
      • 4
      • 5

      举个梨子:

      #include <stdio.h>
      #include <string.h>
      
      int main()
      {
          FILE* f = fopen("C:\\Users\\13040\\Desktop\\test.txt", "w");
      
          fprintf(f, "%d,%s,%lf", 12, "hello", 12.34);
          fclose(f);
          //写入内容:12,hello,12.340000
          return 0;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

    (二)读(注意w和r+模式会擦除内容)

    1. fread():一次读指定字节数

      size_t fread(     //返回值是实际读出的字节数
          void *buffer, //参数1:我们自定义的字符数组,文件读出来的内容装在这里
          size_t size,  //参数2:sizeof(类型)
          size_t count, //参数3:数据数量,参数2与参数3相乘等于读出的字节数
       	FILE *stream  //参数4:文件指针
      );
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      举个例子:

      #include <stdio.h>
      #include <string.h>
      
      int main()
      {
          char str[15] = { 0 };
      
          FILE* f = fopen("C:\\Users\\13040\\Desktop\\test.txt", "r");
          
          fread(str, sizeof(char), 12, f);
          puts(str); //I LOVE YOU !
          
          /*while (fread(str, sizeof(char), 1, f))
          {
              printf("%s", str);// I LOVE YOU !
          }*/
          
          fclose(f);
          return 0;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20

      fread()读写结构体:

      #include <stdio.h>
      
      struct Node
      {
          int id;
          char name[10];
          short age;
          double score;
      };
      
      int main()
      {
          //写操作
          struct Node stu1 = { 13,"张三",20,88.8 };
      
          FILE* f = fopen("C:\\Users\\13040\\Desktop\\test.txt", "w");
          fwrite(&stu1, sizeof(stu1), 1, f);
          fclose(f);
      
          //读操作
          struct Node stu2;
      
          FILE* g = fopen("C:\\Users\\13040\\Desktop\\test.txt", "r");
          fread(&stu2, sizeof(stu1), 1, g);
          fclose(f);
          
          return 0;
      }
      //调试发现:stu2{id=13 name=0x000000af711cfc0c "张三" age=20 ...}成功读取
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
    2. fgets():一次读一行

      char *fgets( char *str,  int n,  FILE *stream );
      
      //返回值:就是str的地址
      //参数1:读出来的数据装在哪儿
      //参数2:最大的读取量,不要超过参数1的长度
      //参数3:文件指针
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

      举个例子:

      #include <stdio.h>
      #include <string.h>
      
      int main()
      {
          char str[20] = "";
      
          FILE* f = fopen("C:\\Users\\13040\\Desktop\\test.txt", "r");
      
          fgets(str, 20, f);
          puts(str);
          fclose(f);
      
          return 0;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
    3. fscanf():格式化读(与fprintf配套使用)

      int fscanf( 
         FILE *stream,        //文件指针
         const char *format [,//和scanf函数一样的参数要求
            argument ]... 
      );
      
      • 1
      • 2
      • 3
      • 4
      • 5

      举个例子:

      #include <stdio.h>
      #include <string.h>
      
      int main()
      {
          int a = 0;
          char str[20] = { 0 };
          double b = 0;
      
          FILE* f = fopen("C:\\Users\\13040\\Desktop\\test.txt", "r");
          
          //先w模式写入,记住字符串连接数字必须用空格隔开,要不然读取的时候字符串不遇空格不停
          //fprintf(f, "%d,%s %lf", 12, "hello", 12.34);
      
          //怎么用fprintf写的,fscanf就得怎么读,格式字符串必须保持一致
          fscanf(f, "%d,%s %lf", &a, str, &b);
      
          printf("%d\n", a);
          printf("%s\n", str);
          printf("%lf", b);
      
          fclose(f);
          
          return 0;
      }
      /*
      12
      hello
      12.340000
      */
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30

    (三)文件游标指针

    为了对读写进行控制,系统为每一个文件设置了一个文件读写游标指针(或称文件读写位置标记),用来指示“接下来要读写的下一个字符的位置”。

    一般情况下,在对文本文件进行顺序读写时,文件游标指针指向文件开头,这时进行读操作,就读第一个字符,然后文件游标指针向后移动一个位置,以此类推,遇到文件尾结束。

    如果是写操作,则每写完一个数据后,文件游标指针顺序向后移动一个位置,然后下一次写操作时把数据写入新的所指位置,以此类推,直到写完全部数据。

    也可以根据需要,人为移动游标指针位置。

    • feof判断文件的游标指针是否位于文件结尾处

      int feof( FILE *stream );
      //参数为文件指针
      //返回值:游标指针没到文件结尾返回 0,到了结尾返回 !0(利用这点可作循环条件)
      
      • 1
      • 2
      • 3
    • fseek设置文件游标指针的位置

      int fseek(    
      FILE *stream,   //参数1:文件指针
         long offset, //参数2:设置文件游标指针指的位置
         int origin   //参数3:具体位置
      ); 
      
      • 1
      • 2
      • 3
      • 4
      • 5

      巨蟹李子:

      fseek(f, 0L, SEEK_SET) 	//设置游标指针指向文件起始位置
      
      fseek(f, 10L, SEEK_SET)	//设置游标指针指向起始位置 向右 挪动10个字节处
      
      fseek(f, 10L, SEEK_CUR)	//设置游标指针在当前位置 向右 挪动10个字节处
      
      fseek(f, -10L, SEEK_CUR)//设置游标指针在当前位置 向左 挪动10个字节处
      
      fseek(f, 0L, SEEK_END)	//设置游标指针指向文件结尾位置(最后一个字符后面)
      
      fseek(f, -10L, SEEK_END)//设置游标指针指向结尾 向左 挪动10个字节处
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    • ftell返回文件游标指针的当前位置

      long ftell( 
         FILE *stream //文件指针
      );
      //返回文件游标指针当前位置的下标(下标从0开始)
      
      • 1
      • 2
      • 3
      • 4
  • 相关阅读:
    详解 sudo usermod -aG docker majn
    72. 编辑距离
    我的创作纪念日,成为创作者的第1024天。| ⑰【知识图谱·跨模态·自监督学习SSL】知识增强型推荐系统,跨模态对比学习方案 | 附:分享两款好用的WOS文献阅读插件
    @Scope 注解失效了?咋回事
    四级作文模板
    vue快速学习01、环境与常用属性标签
    基于Zookeper的hadoop高可用HA精选
    27.基于ADS的不等分威尔金森功分器设计
    A-level放榜,考生整体成绩大滑坡
    计算机毕业设计hadoop++hive微博舆情预测 微博舆情分析 微博推荐系统 微博预警系统 微博数据分析可视化大屏 微博情感分析 微博爬虫 知识图谱
  • 原文地址:https://blog.csdn.net/jiang1126/article/details/125438918