• C语言——文件操作(2)文件的读写操作


            之前,我讲解了文件的基本情况与读写模式,看到这篇博客的小伙伴们先参考这篇博客:

     C语言——文件操作详解(1)_

            接下来,我会继续讲解文件操作的第二大步:文件读/写操作。

    目录

            A.文件的顺序读写

            一.字符输入输出函数 

            1.fputc字符输出函数

            2.代码实践:

             3.字符输入函数 fgetc

            4.代码实践:

           二.字符串输入输出函数

            1.文本行输出函数 fputs—— 将一个字符串写入流中

            2.代码实践:

            3.文本行输入函数 fgets——从流中读取一个字符串 

            4.代码实践: 

            5.文件打开模式:"a"写文件(追加)

           三.格式化输入输出函数

            1.格式化输出函数 fprintf

             2.代码实践:

            3.格式化输入函数 fscanf ——从文件中读取格式化数据

            4.代码实践:

          四.二进制输入输出函数 

             1.二进制输出 fwrite——将数据块写入流中

             2.代码实践:

             3.二进制输入 fread——从流中读取数据

             4.代码实践:

        五.sscanf函数与sprintf函数

            sprintf 

            2.代码实践:

        六.printf与scanf同类型函数对比

        七.流 


    A.文件的顺序读写

    首先,先来看几个常用的读写函数:

    一.字符输入输出函数 

    1.fputc字符输出函数

    int fputc ( int character, FILE * stream );

    参数介绍:

            int character:表示填写要输入文件的字符

            FILE * stream(流):指向标识输出流的 FILE 对象的指针。

    成功后,将返回写入的字符,并且文件指针指向下一个位置等待写入。
    如果发生写入错误,则返回 EOF 并设置错误指示器ferror)。

    2.代码实践:

    1. int main() {
    2. FILE* pf = fopen("test.txt", "w");
    3. //判断文件是否正常打开
    4. if (pf == NULL) {
    5. printf("%s\n", strerror(errno));
    6. return 1;
    7. }
    8. //字符输入函数——fputc()
    9. char ch = 0;
    10. fputc('a', pf);
    11. fputc(';', pf);
    12. //关闭文件
    13. fclose(pf);
    14. pf = NULL;
    15. return 0;
    16. }

            注:每次使用fputc函数都只能往文件中输入一个字符 。

    通过代码调试后,打开test.txt文件,里面会显示刚才输入的两个字符,如下:

    1. #include>
    2. int main() {
    3. FILE* pf = fopen("test.txt", "w");
    4. if (pf == NULL) {
    5. printf("%s\n", strerror(errno));
    6. return 1;
    7. }
    8. //字符输入函数——fputc()——一次写入一个字符
    9. char ch = 0;
    10. fputc('a', pf);//往test.txt文件中输入一个字符
    11. fputc(';', pf);//往文件中输入一个;号字符
    12. for (ch = 'b'; ch <= 'z'; ch++) {
    13. fputc(ch, pf);
    14. }
    15. //关闭文件
    16. fclose(pf);
    17. pf = NULL;
    18. return 0;
    19. }

             代码讲解:因为fputc每使用一次才能往文件中输入一个字符,使用循环可以实现多次输入,如上代码,我循环了25次,输入了b~z 25个字符,经代码调试后,如下:


     3.字符输入函数 fgetc

     参数只有一个,就是文件指针,意为从文件中读取一个字符内容。返回值为整型

    4.代码实践:

    1. int main() {
    2. FILE* pf = fopen("test.txt", "r");
    3. if (pf == NULL) {
    4. printf("%s\n", strerror(errno));
    5. return 1;
    6. }
    7. //字符输出函数——fgetc(),一次读取一个字符
    8. char ch = 0;
    9. ch=fgetc(pf);//往test.txt文件中读取一个字符
    10. printf("%c\n", ch);
    11. ch = fgetc(pf);//往文件中读取第二个字符
    12. printf("%c\n", ch);
    13. ch = fgetc(pf);//往文件中读取第三个字符
    14. printf("%c\n", ch);
    15. ch = fgetc(pf);//往文件中读取第四个字符
    16. printf("%c\n", ch);
    17. fclose(pf);
    18. pf = NULL;
    19. return 0;
    20. }

    如上图代码,fgetc每使用一次,也就能读取一个字符。

            还是使用循环法可以读取文件中的所有内容!如下:

    1. #include
    2. //读文件——"r"
    3. int main() {
    4. FILE* pf = fopen("test.txt", "r");
    5. if (pf == NULL) {
    6. printf("%s\n", strerror(errno));
    7. return 1;
    8. }
    9. //字符输出函数——fgetc(),一次读取一个字符
    10. char ch = 0;
    11. //使用循环方式读取文件字符,一次读一个
    12. while ((ch = fgetc(pf)) != EOF) {
    13. printf("%c ", ch);//可以读取到文件中所有字符
    14. }
    15. fclose(pf);
    16. pf = NULL;
    17. return 0;
    18. }


     二.字符串输入输出函数

    1.文本行输出函数 fputs—— 将一个字符串写入流中(写入后不会自动换行,需要自己加'\n')

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


    函数参数:
    str:                          包含要写入的内容的字符串

    stream(流):        指向标识输出流的 FILE 对象的指针。

    函数作用:

    将 str 所指向的 C 字符串写入
    该函数开始从指定的地址 (str) 复制,直到到达终止空字符 ('\0')。此终止空字符不会复制到流中。

     2.代码实践:

    1. //写一个字符串到文件中
    2. //使用函数fputs_一次写入一个字符串的数据
    3. int main() {
    4. FILE* pf = fopen("test.txt", "w");
    5. if (pf == NULL) {
    6. printf("%s\n", strerror(errno));
    7. return 1;
    8. }
    9. char ch = 0;
    10. fputs("abcd", pf);
    11. fputs("efghi\n", pf);
    12. fputs("jklmn\n", pf);
    13. //关闭文件
    14. fclose(pf);
    15. pf = NULL;
    16. return 0;
    17. }

            代码讲解:第一次执行的fputs函数,它不会换行,需要手动添加\n标志,否则会一直在第一行进行文件的输入填写。代码调试后结果如下:

            注1:第一次使用的fputs函数,字符串"abcd"没有加'\n',所以在第二次输入的字符串会紧挨第一个字符串的末尾位置。

            注2: 每次对test.txt文件进行调试运行时,都会覆盖掉上一次的数据内容。

            例:上一次test.txt中保存的数据是 a;bcdef~z共27个字符,现在换成了abcdefghi (换行) jklmn等内容。

    3.文本行输入函数 fgets——从流中读取一个字符串 

    char * fgets ( char * str, int num, FILE * stream );

    str:                   指向在其中复制字符串读取的 chars 数组的指针。

    num:                要复制到 str 中的最大字符数(包括终止空字符)。

    stream(流):      指向标识输入流的 FILE 对象的指针。

    函数作用:

    中读取字符并将其作为 C 字符串存储到 str 中,直到读取 (num-1) 字符或达到换行符或文件末尾(以先发生者为准)。
    换行符使 fgets 停止读取,但它被函数视为有效字符,并包含在复制到 str 的字符串中。
    终止空字符会自动追加到复制到 str 的字符之后。

    4.代码实践: 

    1. #include
    2. int main() {
    3. FILE* pf = fopen("test.txt", "r");
    4. if (pf == NULL) {
    5. printf("%s\n", strerror(errno));
    6. return 1;
    7. }
    8. char arr[300];
    9. fgets(arr,5,pf);
    10. printf("%s\n", arr);
    11. fgets(arr, 6, pf);
    12. printf("%s\n", arr);
    13. fgets(arr, 6, pf);
    14. printf("%s\n", arr);
    15. //关闭文件
    16. fclose(pf);
    17. pf = NULL;
    18. return 0;
    19. }

    调试结果: 

           

    代码讲解:

           1. 打开test.txt文件,在第一个fgets函数中,表示从文件指针读取5个字符到char arr数组中去。但从结果上看,只读取到abcd4个字符。

            原因:fgets功能是读取一个字符串,函数在按要求读取时,最后一个读到的字符一定为'\0'结束字符,所以输出abcd。如下图:

    2. 当第一个pgets函数读取完字符串后,文件指针默认跳转到文件的下一个内容中,所以第二个fgets函数读取到的字符串紧随其后,输出字符串"efghi"。

    3.为什么第三个fgets函数什么也没有输出?原因:字符串"jklmn"处于第二行,fgets在第二次的使用中遇到'\0',换行符使 fgets 停止读取,无论在怎么使用fgets函数也没法读到。所以什么也不输出。

    若想读到第二行,还是利用循环法读取文件所有内容。

    1. int main() {
    2. FILE* pf = fopen("test.txt", "r");
    3. if (pf == NULL) {
    4. printf("%s\n", strerror(errno));
    5. return 1;
    6. }
    7. //字符输出函数——fgets()——一次读取一行字符
    8. char arr[300];
    9. while (fgets(arr, 300, pf) != NULL) {
    10. printf("%s\n", arr);
    11. }
    12. //关闭文件
    13. fclose(pf);
    14. pf = NULL;
    15. return 0;
    16. }


    此外,再说一说文件打开模式:"a"追加

    5.文件打开模式:"a"写文件(追加)

    1. int main() {
    2. FILE* pf = fopen("test.txt", "a");
    3. if (pf == NULL) {
    4. printf("%s\n", strerror(errno));
    5. return -1;
    6. }
    7. fputs("hello bit!", pf);
    8. //关闭文件
    9. fclose(pf);
    10. pf = NULL;
    11. return 0;
    12. }

    结果如下:


     三.格式化输入输出函数

    1.格式化输出函数 fprintf

    函数参数:

    stream:        指向标识输出流的 FILE 对象的指针

    format:         各类型的输出形式,以%开头的,如%f,%s,%c,%d等

     2.代码实践:

    1. struct S {
    2. char arr[10];
    3. int age;
    4. double score;
    5. };
    6. int main() {
    7. struct S s = { "zhangsan",20,95.56 };
    8. FILE* pf = fopen("test2.txt", "w");
    9. if (pf == NULL) {
    10. printf("%s\n", strerror(errno));
    11. return -1;
    12. }
    13. //printf("%s %d %lf\n", s.arr, s.age, s.score);
    14. fprintf(pf, "%s %d %lf\n", s.arr, s.age, s.score);
    15. //关闭文件
    16. fclose(pf);
    17. pf = NULL;
    18. return 0;
    19. }

    代码讲解fprintf的作用:把结构体变量s中的信息写入到文件test2.txt中.

                    而printf与fprintf的区别在于:fprintf比printf只多了一个参数——文件指针。

    结果如下:

    3.格式化输入函数 fscanf ——从文件中读取格式化数据

    函数参数同上; 

    4.代码实践:

    1. struct S {
    2. char arr[10];
    3. int age;
    4. double score;
    5. };
    6. int main() {
    7. struct S s;
    8. FILE* pf = fopen("test2.txt", "r");
    9. if (pf == NULL) {
    10. printf("%s\n", strerror(errno));
    11. return -1;
    12. }
    13. //scanf("%s %d %lf", s.arr, &(s.age), &(s.score));
    14. fscanf(pf, "%s %d %lf", s.arr, &(s.age), &(s.score));
    15. printf("%s %d %lf\n", s.arr, s.age, s.score);//将读取到的显示出来
    16. //关闭文件
    17. fclose(pf);
    18. pf = NULL;
    19. return 0;
    20. }

    代码讲解: fscanf(pf, "%s %d %lf", s.arr, &(s.age), &(s.score));//从文件中读取出结构体数据。

                       fscanf比scanf也是只多一个文件指针参数。


     四.二进制输入输出函数 

    1.二进制输出 fwrite——将数据块写入流中

    函数参数:

    ptr:     指向要写入的元素数组的指针,转换为 const void*。

    size:   要写入的每个元素的大小(以字节为单位)。

    count:元素数,每个元素的大小为字节大小

    stream: 指向指定输出流的 FILE 对象的指针。

     2.代码实践:

    1. struct S2 {
    2. char arr[20];
    3. int age;
    4. double score;
    5. };
    6. int main() {
    7. struct S2 s = { "张三",25,93.25 };//创建结构体变量信息
    8. FILE* pf = fopen("test2.txt", "wb");
    9. if (pf == NULL) {
    10. printf("%s\n", strerror(errno));
    11. return -1;
    12. }
    13. fwrite(&s, sizeof(struct S2), 1, pf);//将结构体变量中的信息写入文件中除了张三,
    14. //其他都是乱码
    15. //张三以文本形式写进去,以二进制形式写出来是
    16. //一样的
    17. fclose(pf);
    18. pf = NULL;
    19. return 0;
    20. }

     调试结果:

       注:有乱码是因为,数据内容是以二进制形式写入文件,有的东西文件无法失败,出现乱码。 

    3.二进制输入 fread——从流中读取数据

     

     4.代码实践:

    1. struct S2 {
    2. char arr[20];
    3. int age;
    4. double score;
    5. };
    6. int main() {
    7. struct S2 s;
    8. FILE* pf = fopen("test2.txt", "rb");
    9. if (pf == NULL) {
    10. printf("%s\n", strerror(errno));
    11. return -1;
    12. }
    13. fread(&s, sizeof(struct S2), 1, pf);//从文件中读取内容
    14. printf("%s %d %lf\n", s.arr, s.age, s.score);
    15. fclose(pf);
    16. pf = NULL;
    17. return 0;
    18. }


    五.sscanf函数与sprintf函数

    sprintf 

    2.代码实践:

    1. struct S3 {
    2. char arr[10];
    3. int age;
    4. double score;
    5. };
    6. int main() {
    7. struct S3 s = { "张三",25,56.30 };
    8. char a[100] = { 0 };
    9. sprintf(a, "%s %d %lf\n", s.arr, s.age, s.score);
    10. printf("字符串输出:%s\n", a);//数组a中的内容:"张三 25 56.300000"(字符串)
    11. struct S3 tmp = { 0 };
    12. sscanf(a, "%s %d %lf", tmp.arr, &(tmp.age), &(tmp.score));
    13. printf("格式化输出:%s %d %lf\n", tmp.arr, tmp.age, tmp.score);
    14. return 0;
    15. }

    代码讲解://sprintf是将格式化数据转换成字符串放入数组a中

                    //sscanf是将数组a中字符串的内容取出,放入为格式化数据中 

     


    六.printf与scanf同类型函数对比

    任何一个C程序,只要运行起来,会默认打开三个流:
    stdin              标准输入流(键盘)——scanf
    stdout           标准输出流(屏幕)——printf
    stderror        标准错误流(屏幕)

     scanf是针对标准输入的格式化输入语句;              prinf是针对标准输出的格式化输出语句

     fscanf是针对所有输入流的格式化输入语句;         fprintf 是针对所有输出流的格式化输出语句.

     sscanf从一个字符串中转化处一个格式化的数据;sprintf是把一个格式化的数据转化成字符串


    七.流 

    1.刚才很多函数都提到了流这个词,流就是文件指针,下图就是流的作用图解:

            2.打开一个流,将把该流与一个文件或设备连接起来,关闭流将断开这种连接,打开一个文件将返回一个指向FILE结构体类型的指针,该指针记录了控制该流的所有必要信息。       

            3.拿输入来说,stdin就是默认的输入流,通常就是键盘输入。啥意思?就是没有特别说明的话,你的程序就是找键盘要那个需要被复制的文件。stdin就是一个指向键盘这个输入设备的指针。针对这个stdin这个指针,又有对应的函数来执行相印的操作,如果输入的是字符,就用getchar,若是文本则用gets,scanf,二进制数据用fread。 理解了这一个流,其他也是如出一辙。


    好了,关于文件操作的读写函数就介绍到这,大家觉得有用的话点个一键三连吧,下期见!

  • 相关阅读:
    【C++】malloc 和 new 的区别
    线上接口流量突增,快要扛不住了
    springboot10:web开发常用功能(拦截器,文件上传,异常处理)
    uniapp使用@microsoft/signalr(报错“ReferenceError: require is not defined“)
    数据分析从0到1----Matplotlib篇
    云盒子联合深信服,为南京一中打造智慧双模教学资源分享平台
    接口自动化测试框架(pytest+allure+aiohttp+ 用例自动生成)
    FPGA实现UDP传输视频,提供2套verilog工程源码和接收显示上位机程序
    Android 理解/生成/使用/查看 签名(V1-V4)
    数组结构与算法
  • 原文地址:https://blog.csdn.net/weixin_69283129/article/details/126162221