C语言详解(文件操作)2

Hi~!这里是奋斗的小羊,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~
💥💥个人主页:奋斗的小羊
💥💥所属专栏:C语言

🚀本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为展示我的学习过程及理解。文笔、排版拙劣,望见谅。


目录

  • 前言
  • 四、文件的顺序读写
    • 4.1 顺序读写函数介绍
      • 4.1.1 fputc
      • 4.1.2 fgetc
      • 4.1.3 fputs
      • 4.1.4 fgets
      • 4.1.5 fprintf
      • 4.1.6 fscanf
      • 4.1.7 sprintf(操作的不是文件)
      • 4.1.8 sscanf(操作的不是文件)
      • 4.1.9 fwrite
      • 4.1.10 fread
  • 五、文件结束的判定
    • 5.1 被错误使用的feof
    • 5.2 文本文件读取结束
    • 5.3 二进制文件读取结束
  • 六、文件缓冲区
  • 总结

前言

上篇文章中我们初步了解了文件的相关信息,文件的打开和关闭,以及文件的随机读写等
本篇文章将详细介绍一些文件顺序读写函数的作用、特点和用法,使我们更加方便地操作文件,还会讲到如何判定文件的结束等,内容可能有点多,请耐心看完哦


四、文件的顺序读写

4.1 顺序读写函数介绍

下面这些函数都在头文件<stdio.h>中定义

函数名功能适用于
fgetc字符输入函数所有输入流
fputc字符输出函数所有输出流
fgets文本行输入函数所有输入流
fputs文本行输出函数所有输出流
fscanf格式化输出函数所有输入流
fprintf格式化输出函数所有输出流
fread二进制输入文件输入流
fwrite二进制输出文件输出流

4.1.1 fputc

fputc函数的原型如下:

int fputc( int ch, FILE *stream );

fputc函数的功能是:写入字符ch到给定输出流stream

  • ch:要写入的字符
  • stream: 输出流

开始时在当前工程目录底下创建一个文本文档,存入数据:
请添加图片描述

运行下面的代码:

#include <stdio.h>int main()
{//打开文件FILE* pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen");return 1;}//写文件int i = 0;for (i = 'a'; i <= 'z'; i++){//fputc函数一次只能写入一个字符fputc(i, pf);}//关闭文件fclose(pf);pf = NULL;return 0;
}

运行上面的代码后查看文档,可以看到里面的内容已经被修改

请添加图片描述


4.1.2 fgetc

fgetc函数原型如下:

int fgetc( FILE *stream );
  • stream:读取字符的来源

fgetc函数读取正常时返回读取到的字符的ASCII码值,失败时返回EOF

运行下面的代码:

#include <stdio.h>int main()
{//打开文件FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件int ch = 0;//注意:为处理 EOF 需要 int 而非 charwhile ((ch = fgetc(pf)) != EOF){printf("%c ", ch);}//关闭文件fclose(pf);pf = NULL;return 0;
}

运行成功,在终端上打印出 ‘a’ ~ ‘z’:

请添加图片描述

fgetcfputc适用所有输入流和所有输出流,当然包括标准输入流stdin和标准输出流stdout

#include <stdio.h>int main()
{int ch = 0;ch = fgetc(stdin);//从键盘(标准输入流)上读取fputc(ch, stdout);//将字符输出(写)到屏幕(标准输出流)return 0;
}

请添加图片描述


4.1.3 fputs

fputs函数原型如下:

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

fputs函数的功能是:将以NULL结尾的字符串str的每个字符写入到输出流stream,如同通过重复执行fputc,不将 str 的空字符串写入

运行下面的代码:

#include <stdio.h>int main()
{//打开文件FILE* pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen");return 1;}//写文件fputs("Are you ok?", pf);//关闭文件fclose(pf);pf = NULL;return 0;
}

运行成功后查看文档,内容已经被重写:

请添加图片描述

fputs函数在写入字符串的时候是不主动换行的

#include <stdio.h>int main()
{//打开文件FILE* pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen");return 1;}//写文件fputs("Are you ok?", pf);fputs("What can I say? man.", pf);//关闭文件fclose(pf);pf = NULL;return 0;
}

在这里插入图片描述


4.1.4 fgets

fgets函数原型如下:

char* fgets( char *str, int count, FILE *stream );
  • str:指向char型数组元素的指针
  • count:写入的最大字符数(典型的为 str 的长度)
  • stream:读取数据来源的文件流

fgets函数的返回值:成功时为str,失败时为NULL

fgets函数的作用:

  • 从给定文件流读取最多count-1个字符并将它们存储于str所指向的字符数组
  • 若文件尾出现或发现换行符则终止分析,后一情况下 str 将包含一个换行符
  • 若读入字符且无错误发生,则紧随str的最后一个字符后写入空字符'\0'

test.txt文档中的内容改为“abcdefghijklmnopq”:

在这里插入图片描述

调试下面的代码:

#include <stdio.h>int main()
{//打开文件FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件char str[20] = "xxxxxxxxxxxx";fgets(str, 5, pf);printf("%s\n", str);//关闭文件fclose(pf);pf = NULL;return 0;
}

在这里插入图片描述

可以看到,虽然函数fgets确实在数组str中存入了5个字符,但是只读取了文档test.txt实际的4个字符存入数组str中,还有一个是字符‘\0’

也就是说当参数count给的值是5的时候,实际只从文件中读取4个字符

test.txt文档中的内容改为:
在这里插入图片描述

调试下面的代码:

#include <stdio.h>int main()
{//打开文件FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件char str[20] = "xxxxxxxxxxxx";fgets(str, 10, pf);printf("%s\n", str);//关闭文件fclose(pf);pf = NULL;return 0;
}

在这里插入图片描述

可以看到,数组str中并没有存入我们预想的10个字符,所以fgets函数遇到换行符‘\n’会停止读取,并且将‘\n’也存入数组str

当然不管哪种情况最后都会补‘\0’

同样的,fgetsfputs也适用所有输入流和所有输出流,当然也包括标准输入流stdin和标准输出流stdout

#include <stdio.h>int main()
{char str[20] = { 0 };fgets(str, 20, stdin);fputs(str, stdout);return 0;
}

在这里插入图片描述


4.1.5 fprintf

fprintf函数原型如下:

int fprintf( FILE *stream, const char *format, ... );

将结果写入输出流stream

对比printf

int printf( const char *format, ... );

将结果写入输出流stdout

可以看到fprintf函数比printf多了一个参数——文件指针
其中 ...表示可变参数列表,所以函数fprintf也可以有若干个参数

运行下面的代码:

#include <stdio.h>struct S
{char name[20];int age;double weight;
};int main()
{struct S s = { "xiaoshuai", 25, 75.3 };//打开文件FILE* pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen");return 1;}//写文件fprintf(pf, "%s\n%d\n%.1lf\n", s.name, s.age, s.weight);//关闭文件fclose(pf);pf = NULL;return 0;
}

请添加图片描述

可以看到,文档的内容已经被重写


4.1.6 fscanf

fscanf函数的原型如下:

int fscanf( FILE *stream, const char *format, ... );

对比scanf函数:

int scanf( const char *format, ... );

也是多了一个文件指针参数

运行下面的代码:

#include <stdio.h>struct S
{char name[20];int age;double weight;
};int main()
{struct S s = { 0 };//打开文件FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件fscanf(pf, "%s %d %lf\n", s.name, &s.age, &s.weight);//从文件中读取的信息存到结构体s中//注意:从文件中读的时候不要用  %.1lf//s.name是数组名不需要加取地址操作符printf("%s\n%d\n%.1lf\n", s.name, s.age, s.weight);//打印在屏幕上//关闭文件fclose(pf);pf = NULL;return 0;
}

请添加图片描述

当然也可以用fprintf打印:

在这里插入图片描述

fprintffscanf就相当于printfscanf的升级版,功能是在它们两个之上的


4.1.7 sprintf(操作的不是文件)

注意:函数sprintf操作的不是文件,在这里介绍是为了对比

sprintf函数原型如下:

int sprintf( char *buffer, const char *format, ... );

sprintf函数的功能:将结果写入字符串buffer, 如果所写入的字符串(加上终止空字符)超出由 buffer所指向的数组的大小,则行为未定义。

运行下面的代码:

#include <stdio.h>struct S
{char name[20];int age;double weight;
};int main()
{char str[100] = { 0 };struct S s = { "xiaomei", 24, 55.2 };sprintf(str, "%s %d %.1lf", s.name, s.age, s.weight);printf("%s\n", str);return 0;
}

在这里插入图片描述

sprintf其实是将格式化的数据转化为字符串


4.1.8 sscanf(操作的不是文件)

注意:函数sscanf操作的不是文件,在这里介绍是为了对比

sscanf函数的原型如下:

int sscanf( const char *buffer, const char *format, ... );

sscanf函数的功能是从字符数组中提取数据,然后格式化

运行下面的代码:

#include <stdio.h>struct S
{char name[20];int age;double weight;
};int main()
{char str[100] = { 0 };struct S s = { "xiaomei", 24, 55.2 };//将结构体变量s中格式化的数据转化为字符串存入字符数组str中sprintf(str, "%s %d %.1lf", s.name, s.age, s.weight);//printf("%s\n", str);//临时变量struct S tmp = { 0 };//将字符数组str中的数据格式化的存入结构体变量tmp中sscanf(str, "%s%d%lf", tmp.name, &tmp.age, &tmp.weight);fprintf(stdout, "%s %d %.1lf", tmp.name, tmp.age, tmp.weight);return 0;
}

请添加图片描述


  • scanf/printf针对标准输入流 / 标准输出流的格式化输入 / 输出函数
  • fscanf/fprintf针对所有输入流 / 所有输出流的格式化输入 / 输出函数
  • sscanf/sprintf将格式化的数据转换为字符串 / 将字符串转化为格式化的数据

4.1.9 fwrite

fwrite函数原型如下:

size_t fwrite( const void *buffer, size_t size, size_t count,FILE *stream );

fwrite函数的参数:

  • buffer:指向数组中要被写入的首个对象的指针
  • size:每个对象的大小
  • count:要被写入的对象数
  • stream:指向输出流的指针

fwrite函数的返回值:成功写入的对象数,若错误发生则可能小于count

fwrite函数的作用:将buffer指向空间内count个大小为size的元素数据写到输出流stream(文件)中

运行下面的代码:

#include <stdio.h>struct S
{char name[20];int age;double weight;
};int main()
{struct S s = { "xiaochou", 23, 65.7 };//打开文件FILE* pf = fopen("test.txt", "wb");if (pf == NULL){perror("fopen");return 1;}//写文件//以二进制的形式写到文件中fwrite(&s, sizeof(struct S), 1, pf);//关闭文件fclose(pf);pf = NULL;return 0;
}

请添加图片描述

运行成功后文档内是我们看不懂的二进制的信息


4.1.10 fread

fread函数的原型如下:

size_t fread( void *buffer, size_t size, size_t count,FILE *stream );

fread函数的参数:

  • buffer:指向要读取的数组中首个对象的指针
  • size:每个对象的字节大小
  • count:要读取的对象数
  • stream:读取来源的输入文件流

fread函数的返回值:成功读取的对象数,若出现错误或文件尾条件,则可能小于count

fread函数的作用:从输入流stream(文件)中读取count个大小为size个字节的数据存到buffer指向的空间内

运行下面的代码:

#include <stdio.h>struct S
{char name[20];int age;double weight;
};int main()
{struct S s = { 0 };//打开文件FILE* pf = fopen("test.txt", "rb");if (pf == NULL){perror("fopen");return 1;}//写文件//读取二进制的信息到文件中fread(&s, sizeof(struct S), 1, pf);//打印结构s的成员fprintf(stdout, "%s\n%d\n%.1lf\n", s.name, s.age, s.weight);//关闭文件fclose(pf);pf = NULL;return 0;
}

请添加图片描述

可以看到fread函数又将二进制的信息读文件中变成了我们可以看懂的信息


五、文件结束的判定

5.1 被错误使用的feof

文件读取结束有两个原因:

    1. 遇到文件结尾
    1. 遇到错误

feof函数的原型如下:

int feof( FILE *stream );

feof函数的返回值:若已抵达流尾则为非零值,否则为 ​0​

feof函数的作用是:当文件已经读取结束的时候,判断读取结束的原因是否是遇到文件结尾

但是这个函数经常被用错,部分人以为feof函数的作用是判断文件读取是否结束,其实不是的


5.2 文本文件读取结束

文本文件读取是否结束,判断返回值:

  • fgetc:判断是否为EOF
  • fgets:判断是否为NULL

例如:

#include <stdio.h>int main()
{//打开文件FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件int ch = 0;//注意:为处理 EOF 需要 int 而非 charwhile ((ch = fgetc(pf)) != EOF){printf("%c ", ch);}//判断是什么原因结束的if (ferror(pf)){puts("I/O error when reading");}else if (feof(pf)){puts("End of file reached successfully");}//关闭文件fclose(pf);pf = NULL;return 0;
}

5.3 二进制文件读取结束

二进制文件读取是否结束,判断返回值是否小于实际要读的个数。
例如:

#include <stdio.h>struct S
{char name[20];int age;double weight;
};int main()
{struct S s = { 0 };//打开文件FILE* pf = fopen("test.txt", "rb");if (pf == NULL){perror("fopen");return 1;}//读取二进制的信息到文件中size_t num = fread(&s, sizeof(struct S), 1, pf);if (num == 1){puts("Array read successfully, contents:");}else if (feof(pf)){printf("Error reading test.bin: unexpected end of file\n");}else if (ferror(pf)){perror("Error reading test.bin");}//关闭文件fclose(pf);pf = NULL;return 0;
}

六、文件缓冲区

ANSIC标准采用“缓冲文件系统”处理数据文件的,所谓缓冲文件系统是指系统自动的在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。

如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区,充满缓冲区后再逐个地将数据送到程序数据区(程序变量等),缓冲区的大小根据C编译系统决定。


总结

  • 文件读写函数在编程中具有非常重要的作用,能够帮助程序员实现数据的持久化存储、数据交换、日志记录、配置文件处理等功能,提高程序的灵活性、可维护性和可扩展性,从而提升整个程序的质量和效率

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/26109.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSS id选择器

目录 任务描述 相关知识 id选择器 id选择器语法 类选择器与id选择器的区别 编程要求 任务描述 在本关中&#xff0c;你将通过id选择器的方式完成页面菜单栏样式布局&#xff0c;栏目导航等任务。 完成任务之后&#xff0c;基本页面效果如下&#xff1a; 动态效果如下&am…

IDEA:配置Golang的开发环境

1、下载&安装 进入GO的官网下载对应的GO 我们可以下载安装版&#xff0c;不过本人习惯下载解压版&#xff0c;这个因个人而异 2、配置环境变量 GOBIN : %GOROOT%\bin GOPATH : D:\MyGo 工作区间 GOROOT : D:\Program Files\Go GOJDK地址PATH: %GOBIN% ; %GOROOT%\bin ; …

生成性人工智能模型:行业和当局的机会和风险

1 目标受众和本文档目的 BSI&#xff08;德国联邦信息安全办公室&#xff09;通过本出版物面向考虑在其工作流程中使用生成性AI模型的公司和当局&#xff0c;以提高对这些模型的基本安全意识&#xff0c;并促进它们的安全使用。为此&#xff0c;除了机会外&#xff0c;它还突出…

Spring Boot整合Redis实现发布/订阅功能

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

Kimichat使用案例012:用Kimichat拆解雷军在小米汽车SU7发布会上的演讲技巧

文章目录 一、介绍二、输入内容三、输出内容四、继续追问五、继续回答六、讲解对比七、对比回答相似之处:不同之处:八、职场人士如何借鉴九、借鉴内容一、介绍 小米SU7发布会可以说是非常成功。雷军的演讲技巧是发布会成功的重要因素之一,很值得借鉴学习。 可以借助Kimichat…

git服务器gitblit安装

1、下载 Gitblit 2、下载完后解压&#xff1a; 3、配制&#xff1a; 保存&#xff0c;退出编辑。 4、运行cmd&#xff0c;启用gitblit。 5、根据运行后的提示&#xff0c;也就是我们之间设置的port9990打开&#xff1a; 输入admin,admin就可以登录&#xff0c;这个账号密码&a…

[大模型]GLM4-9B-chat Lora 微调

本节我们简要介绍如何基于 transformers、peft 等框架&#xff0c;对 LLaMA3-8B-Instruct 模型进行 Lora 微调。Lora 是一种高效微调方法&#xff0c;深入了解其原理可参见博客&#xff1a;知乎|深入浅出 Lora。 这个教程会在同目录下给大家提供一个 nodebook 文件&#xff0c…

IP协议报文格式

IP协议报文格式 一: 报头格式1.1 : 4位版本1.2 : 4位首部长度1.3 : 8位服务类型 :1.4 : 16位总长度(字节数)1.5 : 8位生存时间(TTL)1.6 : 8 位协议1.7 : 32 位源IP / 32 位目的IP 一: 报头格式 1.1 : 4位版本 现在使用的也就只有IPv4,IPv6 1.2 : 4位首部长度 以 4字节为单位…

Xilinx(AMD) vivado对FPGA网表文件进行功能仿真的方法

1 概述 在FPGA开发中很多商用IP核出于知识产权保护的目的&#xff0c;不提供源代码&#xff0c;而是提供综合后的FPGA网表。由于没有源代码&#xff0c;也无法对网表文件直接进行仿真的操作来验证功能&#xff0c;此时需要独立的仿真模型文件。 本文介绍在Xilinx(AMD) vivado软…

【解决问题】QApplication: No such file or directory,C++ 使用Qt或项目未正确加载Cmake报错

运行环境&#xff1a; Clion编译&#xff0c;构建C工程项目报错QApplication: No such file or directory 问题描述 QApplication: No such file or directory 引用的#include <QApplication>飘红 解决方案 1、Qt没有安装正确&#xff0c;请使用对应版本的Qt。或编译…

激光点云配准算法——Cofinet / GeoTransforme / MAC

激光点云配准算法——Cofinet / GeoTransformer / MAC GeoTransformer MAC是当前最SOTA的点云匹配算法&#xff0c;在之前我用总结过视觉特征匹配的相关算法 视觉SLAM总结——SuperPoint / SuperGlue 本篇博客对Cofinet、GeoTransformer、MAC三篇论文进行简单总结 1. Cofine…

Nginx之正向代理配置示例和说明

一、NGINX正向代理功能简介 Nginx的正向代理功能允许局域网中的客户端通过代理服务器访问Internet资源。具体来说&#xff0c;Nginx作为一种流行的Web服务器和反向代理服务器&#xff0c;在正向代理方面的应用也相当实用。以下是其正向代理功能的几个关键点&#xff1a; 访问外…

使用手机做PC机摄像头

准备工作&#xff1a; 带摄像头的安卓手机一部模拟相机软件&#xff1a;Iriun 、DroidCam 、IP摄像头pythonopencv 一、Iriun 1、分别在PC和手机上安装 2、手机和PC在同一个局域网 3、分别打开PC和手机端软件&#xff0c;电脑端就可以使用手机相机 ​ 二、 DroidCam 1、…

开发小Tips:切换淘宝,腾讯,官方,yarn,cnpm镜像源,nrm包管理工具的具体使用方式(方便切换镜像源)

由于开发中经常要下载一些软件或者依赖&#xff0c;且大多数的官方源的服务器都在国外&#xff0c;网速比较慢&#xff0c;国内为了方便&#xff0c;国内一些大厂就建立一些镜像&#xff0c;加快下载速度。 1.各大镜像源的切换&#xff1a; 切换淘宝镜像源&#xff1a; npm …

数据挖掘丨轻松应用RapidMiner机器学习内置数据分析案例模板详解(上篇)

RapidMiner 案例模板 RapidMiner 机器学习平台提供了一个可视化的操作界面&#xff0c;允许用户通过拖放的方式构建数据分析流程。 RapidMiner目前内置了 13 种案例模板&#xff0c;这些模板是预定义的数据分析流程&#xff0c;可以帮助用户快速启动和执行常见的数据分析任务。…

Zabbix6.0自动发现Linux服务器并添加主机

文章目录 一、整体流程二、操作过程 一、整体流程 Zabbix自动发现主机功能是Zabbix监控系统的一个重要功能&#xff0c;它能够自动发现并添加新的主机到监控系统中&#xff0c;从而减少人为繁琐的操作&#xff01; 步骤操作1️⃣ 第一步创建自动发现规则2️⃣ ​第二步创建自…

安卓事件交互(按键事件、触摸事件、手势识别、手势冲突处理)

本章介绍App开发常见的以下事件交互技术&#xff0c;主要包括&#xff1a;如何检测并接管按键事件&#xff0c;如何对触摸事件进行分发、拦截与处理&#xff0c;如何根据触摸行为辨别几种手势动作&#xff0c;如何正确避免手势冲突的意外状况。 按键事件 本节介绍App开发对按…

[qt] qt程序打包以及docker镜像打包

目录 一 环境准备: 1.1 qt环境 1.2 linuxdeplouqt打包工具 二 qt包发布: 2.1 搜索链接库 2.2 应用程序APP打包 2.3 发布 三 docker镜像包发布 3.1 环境准备 3.2 镜像生产脚本 3.3 加载镜像并运行docker容器 一 环境准备: qt环境linuxdeployqt打包工具docker环境 1…

demo xshell (程序替换 工作目录 内建命令)

1.程序替换 在学习完一些列的进程替换接口之后我们大概就能知道&#xff0c;我们的环境变量以及命令行参数是如何传递给子进程的&#xff0c;这些参数是我们在调用进程替换时就传给了子进程的数据。 那么如果我们自己要实现一个简单的命令行解释器&#xff0c;我们是不是首先…

stm32MP135裸机编程:使用USB/UART烧录程序到SD卡并从SD卡启动点亮一颗LED灯

0 参考资料 轻松使用STM32MP13x - 如MCU般在cortex A核上裸跑应用程序.pdf STM32CubeProgrammer v2.16.0 烧录需要的二进制文件1 烧录到SD卡需要哪些文件 参考《轻松使用STM32MP13x - 如MCU般在cortex A核上裸跑应用程序》&#xff0c;烧录需要的SD卡文件如下&#xff1a; &a…