【C语言】文件操作详解2(文件的顺序读写操作)

【C语言】文件操作详解2(文件的顺序读写操作)

前言:
书接上回,由于文章过长,所以分了三篇文
若内容对大家有所帮助,可以收藏慢慢看,感谢大家支持
谢谢大家 ! ! !

上期给大家介绍了文件的打开与关闭
这期我们就来聊聊文件的顺序读写操作

一、引子

文件开关的标准流程:

  1. 打开文件(创建文件信息区)
  2. 读写文件(通过文件指针操作)
  3. 关闭文件(释放资源)

在打开文件后,就是我们的读写文件了

首先,我们要知道什么是 " 读 " ,什么是 " 写 "****(很重要很重要,易错)
" 读 ":输入数据,将数据从磁盘(文件)中输入到内存中存储
" 写 ":输出数据,将数据从内存中输出到磁盘(文件)中存储
且一定要注意:
先要确定你要进行什么操作(读 & 写)
再选择你的打开方式(" r " & " w ")

(弄混会运行错误)

读写文件时肯定少不了很多函数
小编在这里也是给大家收集了一些常见的函数,希望对大家有用

本期我们就来一 一化解这些函数

二、众多函数介绍

如下图:

大家想要自行了解这些函数的细节也可以到c++官网上去找
小编本人也是经常使用

https://legacy.cplusplus.com/

1.单字符输入输出函数(fgetc & fputc)

讲函数我们先讲输出,再讲输入(下同)

(1)fputc(字符输出函数)

fputc可将内存中的单个字符输出到磁盘(文件)中

fputc语法:
int fputs ( int character, FILE * stream ) ;
character表示要输出的一个字符
stream表示接收字符的文件的文件指针
例如:
fputc('a', pf); 输出数据到 pf 所指向的文件中
fputc的多字符同时输出:
fputc('a', pf);
fputc('b', pf);
fputc('c', pf);
这样就可以做到fputc的多字符同时输出

完整代码演示:

(内有注释,不懂就看)

c 复制代码
#include<stdio.h>

int main()
{
    FILE* pf = fopen("test.txt", "w");
    if (pf == NULL)
    {
        perror("fopen");
        //打印出错误信息
        return 0;
        //返回状态码 1 表示异常退出
    }

    fputc('a', pf);//输出数据
    fputc('b', pf);//同时输出多个数据
    fputc('c', pf);
    fputc('d', pf);
    fputc('e', pf);
    fputc('f', pf);
    fputc('g', pf);


    fclose(pf);//关闭文件
    pf = NULL;//置为NULL空指针

    return 0;
}

运行结果:
文件被输入了字符 " abcdefg "

但是,在多组同时输出时,有一个小小的疑问

为什么每个字符都是连续排列的?

难道每次写入字符后文件光标会自动后移吗?
事实也确实如此,在每次写入字符后文件光标会自动后移

所以每个字符都是连续的

(2)fgetc(字符输入函数)

fgetc可将磁盘(文件)的单个字符输出到内存的变量中

fgetc语法:
int fgetc ( FILE * stream );
stream表示接收字符的文件的文件指针

代码演示:

现在,我们先将文件中存放 " abcdefg "

再用fgetc读取文件的数据
注意:
因为fgetc函数一次性只能读取一个字符
所以我们可以加入一个循环来读取多个字符

(内有注释,不懂就看)

c 复制代码
#include<stdio.h>

int main()
{
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        //打印出错误信息
        return 0;
        //返回状态码 1 表示异常退出
    }
    for(int i=1;i<=7;i++)
    {
        printf("%c ", fgetc(pf));
        //加入一个循环来读取多个字符并打印
    }
    printf("\n\n");
    fclose(pf);//关闭文件
    pf = NULL;//置为NULL空指针

    return 0;
}

运行结果:(事先在文件中存储了数据)

以上的代码通过了一个循环来达到读取并打印多个字符的结果

当然还有一种改进代码也可以实现
这里就要用到fgetc的返回值

fgetc的返回值:
int fgetc ( FILE * stream );
正常读取时:返回读到字符的ASCLL码值
读取失败时:返回EOF

在文件操作中,EOF 是 "End of File"(文件结束)的缩写,用于指示文件的结束

代码演示:(利用fgetc的返回值)

(内有注释,不懂就看)

c 复制代码
#include<stdio.h>

int main()
{
    char ch;
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        //打印出错误信息
        return 0;
        //返回状态码 1 表示异常退出
    }
    while ((ch = fgetc(pf)) != EOF)
    //当返回值不为EOF时,继续
    //可以把所有字符打印出来
    {
        printf("%c ", ch);
    }
    printf("\n\n");
    fclose(pf);//关闭文件
    pf = NULL;//置为NULL空指针

    return 0;
}

运行结果:

当然,代码结果是一样的,但代码要更加高效精简

2.字符串输入输出函数(fgets & fputs)

(1)fputs(字符串输出函数)

fputs可将内存中的字符串输出到磁盘(文件)中

fputs语法:
int fputs ( const char * str, FILE * stream );
str表示要输出的字符串
stream表示接收字符串的文件的文件指针
例如:
fputs("abcdefg\n", pf); (可加换行符 \n )
输出数据到 pf 所指向的文件中

代码演示:
注意,fputs 不会自动换行,要手动换行

(内有注释,不懂就看)

c 复制代码
#include<stdio.h>

int main()
{
    char ch;
    FILE* pf = fopen("test.txt", "w");
    if (pf == NULL)
    {
        perror("fopen");
        //打印出错误信息
        return 0;
        //返回状态码 1 表示异常退出
    }

    fputs("Hi\n", pf);//手动换行
    fputs("I am a student", pf);

    printf("\n\n");
    fclose(pf);//关闭文件
    pf = NULL;//置为NULL空指针

    return 0;
}

运行结果:

可以看到,输出时手动换行成功

(2)fgets(字符串输入函数)

fgets可将内存中的字符串输入到磁盘(文件)中

fgets语法:
char * fgets ( char * str, int num, FILE * stream );
str指向字符数组的指针,用于存储读取的字符串
num表示最大读取字符个数
stream表示接收字符串的文件的文件指针
例如:
fgets(str, 20, pf);
将数据输入到 str

但使用fgets有两个要注意的点:

一、fgets读取字符时不会真的读取num个字符,在读取到的字符串的末尾还会存储一个 " \0 "

代码演示:
先在新建文件中写20个字符,这里我写的是
(11112222333344445555)方便观察
再读取到str中,最后打印出来

(内有注释,不懂就看)

c 复制代码
#include<stdio.h>

int main()
{
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        //打印出错误信息
        return 0;
        //返回状态码 1 表示异常退出
    }

    char str[20];
    fgets(str, 20, pf);

    printf("%s", str);//打印读取的字符串

    printf("\n\n");
    fclose(pf);//关闭文件
    pf = NULL;//置为NULL空指针

    return 0;
}

运行结果:

可以看到,本应该的打印20个字符却少了一个变成了19个
这就是因为在读取到的字符串末尾还会存储一个 " \0 "
故实际只存储 num-1 个字符

二、fgets读取时遇到换行符时停止读取不管下一行还有多少字符

代码演示:

先在新建文件中写两行字符
这里我写的两行分别是(Hello)和(world)方便观察

再读取到str中,最后打印出来
代码:

(内有注释,不懂就看)

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

int main()
{
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        //打印出错误信息
        return 0;
        //返回状态码 1 表示异常退出
    }

    char str[20];
    fgets(str, 20, pf);

    printf("%s", str);//打印读取的字符串

    printf("\n\n");
    fclose(pf);//关闭文件
    pf = NULL;//置为NULL空指针

    return 0;
}

运行结果:

可以看到,str 接收数据时只接收了第一行的" Hello ",而第二行不会读取
所以可得,fgets读取时遇到换行符时停止读取不管下一行还有多少字符

3.格式化输入输出函数(fscanf & fprintf)

(1)fprintf(格式化输出函数)

fprintf可将任意类型的数据从内存中输出到磁盘(文件)中

fprintf语法:
int fprintf ( FILE * stream, const char * format, ... );
stream表示文件的文件指针
format是输出的形式(%d,%f,%s······)
最后的...是可变参数列表,可一个或多个变量

代码演示:
演示如何用fprintf将数据输出到文件中

(内有注释,不懂就看)

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

int main()
{
    FILE* pf = fopen("test.txt", "w");
    if (pf == NULL)
    {
        perror("fopen");
        //打印出错误信息
        return 0;
        //返回状态码 1 表示异常退出
    }
    char name[20]="xiaobai";
    int age=18;
    float score=8.29;
    //定义变量名将要输出的数据写入

    fprintf(pf, "%s %d %.2f", name, age, score);
    //输出数据,将数据输出到磁盘(文件)中

    printf("\n\n");
    fclose(pf);//关闭文件
    pf = NULL;//置为NULL空指针

    return 0;
}

运行结果:

可见,我们将变量中的数据输出到了文件中,且分别输出了字符串、整型、浮点型
说明fprintf函数可以格式化输出数据(输出任何类型数据)到磁盘(文件)中

(2)fscanf(格式化输入函数)

fscanf可将任意类型的数据从磁盘(文件)中输入到内存中

fscanf语法:
int fscanf ( FILE * stream, const char * format, ... );
stream表示文件的文件指针
format是输出的形式(%d,%f,%s······)**
最后的...是可变参数列表的地址,可一个或多个变量的地址

代码演示:
现在,我们来演示如何用fscanf函数将数据从文件中输入到内存中的变量中
首先,我们创建一个文件,写入一些数据
(这里我写的是xiaobai 18 8.29
(写了三个数据,分别是字符串,整型,浮点型)

如下:

然后运行代码将数据输入到早已定义好的变量中:

(内有注释,不懂就看)

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

int main()
{
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)
    {
        perror("fopen");
        //打印出错误信息
        return 0;
        //返回状态码 1 表示异常退出
    }
    char name[20];
    int age;
    float score;
    //定义三个变量名用于接收数据

    fscanf(pf, "%s %d %f", &name, &age, &score);
    //通过变量的地址将数据储存
    //读取数据,将数据存在变量中

    printf("%s %d %.2f", name, age, score);
    //将变量一一打印验证效果

    printf("\n\n");
    fclose(pf);//关闭文件
    pf = NULL;//置为NULL空指针

    return 0;
}

运算结果:

可见,我们将文件中的数据输出到了内存的变量中
且分别输入了字符串、整型、浮点型,最后打印出
说明fscanf函数可以格式化输入数据(输入任何类型数据)从文件中输入到内存的变量

三 、补充一些文件打开方式(二进制文件读写)

之前,我给大家讲解了" r " , " w , " a " 三种文件打开方式
现在,给大家补充一些涉及到二进制文件的读写

1.二进制文件是什么?

上一期我们讲解了文本文件与二进制文件的区别
本篇也不赘述,大家可自行查看

【C语言】文件操作详解1(文件的打开与关闭)

2. " rb " (只读)

为了输入数据,打开一个二进制文件 ( 若文件不存在,就报错 )
例如:FILE* pf = fopen("test.txt", "rb");

3. " wb " (只写)

为了输出数据,打开一个二进制文件 ( 若文件不存在,就新建一个文件 )
例如:FILE* pf = fopen("test.txt", "wb");

4. " ab " (追加)

为了在一个二进制文件末尾添加数据 ( 若文件不存在,就新建一个文件 )
例如:FILE* pf = fopen("test.txt", "ab");

当然,这里先简单介绍,待会再用代码进行演示

四、继续函数介绍(二进制输入输出)

1.fwrite(二进制输出函数)

将内存中的数据以二进制形式输出到文件中

fwrite语法:
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
ptr为指向要输出的元素数组的指针

size表示每个要输出元素的字节大小
count表示要输出多少个元素

stream表示接收数据的文件的文件指针

代码演示:

(内有注释,不懂就看)
现在,我们定义一个结构体类型,再将结构体中的数据输出到文件中

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

struct Stu
{
    char name[20];
    int age;
    float score;
}S1;//定义结构体

int main()
{
    struct Stu S1 = { "xiaobai",18,8.29 };
    //初始化结构体

    FILE* pf = fopen("test.txt", "wb");
    //打开文件

    if (pf == NULL)
    {
        perror("fopen");
        //打印出错误信息
        return 0;
        //返回状态码 1 表示异常退出
    }

    fwrite(&S1, sizeof(struct Stu), 1, pf);//将结构体中的数据输出到文件中
    //第一个参数是结构体的地址
    //第二个参数是该结构体的大小
    //第三个参数是要输出几个元素
    //第四个参数是文件指针

    printf("\n\n");
    fclose(pf);//关闭文件
    pf = NULL;//置为NULL空指针

    return 0;
}

运行结果:

可以看到,文件中出现了很多乱码
其实这就是二进制序列,只是转换成文本文件我们看不懂
我们依靠fwrite函数,可将内存中的数据以二进制形式输出到文件中

2.fread(二进制输入函数)

将文件中的二进制数据输出到内存中

fread语法:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
ptr为指向要输入的元素数组的指针

size表示每个要输入元素的字节大小
count表示要输入多少个元素

stream表示文件的文件指针
可翻译为:
stream所指向的文件中读取count个大小为size个字节的数据,并存放在ptr指向的空间中

代码演示:
现在我运行代码读取之前fwrite输出形成的二进制文件
最后打印看看结果如何,是不是之前结构体的数据

(内有注释,不懂就看)

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

struct Stu
{
    char name[20];
    int age;
    float score;
}S;//定义结构体

int main()
{
    FILE* pf = fopen("test.txt", "rb");
    //打开文件

    if (pf == NULL)
    {
        perror("fopen");
        //打印出错误信息
        return 0;
        //返回状态码 1 表示异常退出
    }

    fread(&S, sizeof(struct Stu), 1, pf);//将文件中的数据输入到结构体中
    //第一个参数是结构体的地址
    //第二个参数是该结构体的大小
    //第三个参数是要输入几个元素
    //第四个参数是文件指针

    printf("%s %d %.2f", S.name, S.age, S.score);
    //将读取到的数据打印出来验证结果

    printf("\n\n");
    fclose(pf);//关闭文件
    pf = NULL;//置为NULL空指针

    return 0;
}

运行结果:

结果显示,读取数据成功,是之前的数据
所以,fread可将文件中的二进制数据输出到结构体中

3. fwrite 和 fread 的返回值

fwrite 和 fread 的返回值是实际输入或输出的总个数

结语

本期资料来自于:

https://legacy.cplusplus.com/

OK,本期的文件操作详解到这里就结束了
由于文章过长,所以分了三篇文
下期我们讲解文件的随机读写操作和其他补充

若内容对大家有所帮助,可以收藏慢慢看,感谢大家支持
本文有若有不足之处,希望各位兄弟们能给出宝贵的意见。谢谢大家!!!
新人,本期制作不易希望各位兄弟们能动动小手,三连走一走!!!
支持一下(三连必回QwQ)

相关推荐
狐571 小时前
2025-12-03-LeetCode刷题笔记-3625-统计梯形的数目-II
笔记·leetcode
weixin_462446231 小时前
使用 Python + Tkinter + openpyxl 实现 Excel 文本化转换
开发语言·python·excel
大袁同学1 小时前
【C++完结篇】:深入“次要”但关键的知识腹地
开发语言·数据结构·c++·算法
少许极端1 小时前
算法奇妙屋(十六)-BFS解决边权为1的多源最短路径问题
算法·bfs·队列·图解算法·边权为1的多源最短路径问题·宽度优先遍历
韩立学长1 小时前
基于协同过滤算法的宠物收养系统f27ny63s(程序、源码、数据库、调试部署方案及开发环境)系统界面展示及获取方式置于文档末尾,可供参考。
数据库·算法·宠物
明洞日记1 小时前
【数据结构手册006】映射关系 - map与unordered_map的深度解析
数据结构·c++
廋到被风吹走1 小时前
【JDK版本】JDK1.8相比JDK1.7 JVM(Metaspace 与 G1 GC)
java·开发语言·jvm
2501_915106321 小时前
iPhone 耗电异常全面诊断指南,构建多工具协同的电量分析与优化体系
android·ios·小程序·https·uni-app·iphone·webview