文件操作详解:fgetc,fputc,fgets,fputs,fscanf,,fprintf,fread,fwrite的使用和例子 C语言

news2024/12/23 23:31:44

前言

        在日常应用中,我们为了持续的使用一些数据,为了让数据可以在程序退出后可以保存并正常使用,引入了文件的概念和操作。本文分享了一些常用的文件操作函数的使用方法和各自的区别。

一、常用文件顺序读写函数

下面例程所使用的VS工程代码见:👇

fgetc fputc fgets fputs fscanf fprintf fread fwrite文件操作函数使用例程代码

常用的文件操作函数
功能函数名用于

字符输入函数

fgetc

所有输入流

字符输出函数

fputc

所有输出流

文本行输入函数

fgets

所有输入流

文本行输出函数

fputs

所有输出流

格式化输入函数

fscanf

所有输入流

格式化输出函数

fprintf

所有输出流

二进制输入

fread

文件

二进制输出

fwrite

文件

二、字符操作函数 fgetc 和 fputc

fgetc

c在这里指的是char

官方解释如上图

  • 从流中获取字符
  • 返回指定流的内部文件位置指示符当前指向的字符。然后将内部文件位置指示符推进到下一个字符
  • 如果流在被调用时位于文件的末尾,则该函数返回 EOF 并为流设置文件结束指示器(feof)
  • 如果发生读错误,该函数返回EOF并设置流的错误指示器(error)
  • Fgetc  getc 是等价的,除了 getc 可以在某些库中作为宏实现

为此我们写了个文件

在确保了文件可以有内容读取后,我们编程实现观察结果,我们以读取的方式打开文件,然后使用 ch 变量挨个读取文件中的字符并且打印。

int char_operation1(void)
{
	FILE* pf = fopen("data1.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//读文件
	int ch = fgetc(pf);
	printf("%c", ch);
	ch = fgetc(pf);
	printf("%c", ch);
	ch = fgetc(pf);
	printf("%c", ch);
	ch = fgetc(pf);
	printf("%c", ch);
	ch = fgetc(pf);
	printf("%c", ch);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
	
}

调用此函数并获取结果如下

  • 综上:fgetc 函数可以挨个读取文件中的字符,我们可以定义一个变量来接收 fgets 的返回值(字符的ASCII码)然后进行输出等操作

  • 在使用该函数的时候,我们只需要将文件指针(流)作为参数传给函数,然后我们就可以得到一个字符的ASCII码

fputc

官方解释如上图

  • 将字符写入流
  • 将一个字符写入流并推进位置指示器
  • 字符被写入流的内部位置指示器所指示的位置,然后自动向前移动一个

在实验前创建一个空白的文件

int char_operation2(void)
{
	//打开文件
	FILE* pf = fopen("data2.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//写文件
	fputc('a', pf);
	fputc('b', pf);
	fputc('c', pf);
	fputc('d', pf);
	fputc('e', pf);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

运行后:

通过 fputc 函数挨个对文件输入了从 ‘a’ 到 ‘e’ 的字符 

综合上述操作,我们可以得出结论,fputc 函数可以挨个字符的对文件进行写入的操作,函数内部需要注意的有俩个参数

  1. 要写入的字符
  2. 要写入文件的文件指针(流)

三、文本行操作函数fgets 和 fputs

fgets

s指的是string

  • 从流中获取字符串
  • 从流中读取字符,并将其作为C字符串存储到 str 中,直到读取 (num-1) 个字符,或者到达换行符或文件结束符,以先发生的为准
  • 换行符使 fgets 停止读取,但它被函数认为是一个有效字符,并包含在复制到 str 的字符串中。
  • 在复制到 str 的字符之后,将自动追加一个终止 null 字符。
  • 请注意,fgets  gets 有很大的不同:fgets 不仅接受流参数,而且允许指定 str 的最大长度,并在字符串中包含任何结束换行符。

提前准备一个txt文件

int string_operation1(void)
{
	//打开文件
	FILE* pf = fopen("data3.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//读文件
	char arr[100] = { 0 };
	fgets(arr, 100, pf);
	printf("%s", arr);

	fgets(arr, 100, pf);
	printf("%s", arr);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

运行结果如下:

根据输出结果,我们可以发现,一条 fgets 函数可以读取一行的内容,但是在使用的时候需要注意设置一个字符数组来接收字符串,函数在使用时,一共有三个参数

  1. 要传入数组的地址
  2. 要复制到字符串中的最大字符数
  3. 文件指针(流)

fputs

  • 将字符串写入流
  • 将由 str 指向的C字符串写入流
  • 函数从指定的地址 (str) 开始复制,直到到达结束的空字符 ('\0'),这个终止的空字符不会复制到流中
  • 注意,fputs 与 puts 的不同之处不仅在于可以指定目标流,而且 fputs 不会写入额外的字符,而 puts 会自动在末尾附加一个换行符
int string_operation2(void)
{

	//打开文件
	FILE* pf = fopen("data4.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//写文件
	char arr[] = "hello world\n";
	fputs(arr, pf);

	fputs("Deadly Bug", pf);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

首先还是设定一个空白内容的 data.txt 的文件

运行结果如下

根据运行结果,我们可以判断, fputs 函数一次性可以对文件写入一行字符串,只要声明字符串的内容或者地址,都可以进行写入,它的俩个参数分别如下:

  1. 要写入的字符串的内容或者地址
  2. 要写入的文件指针(流) 

四、格式化文件操作函数fscanf 和 fprintf

fscanf

  • 从流中读取格式化的数据
  • 从流中读取数据,并根据参数格式将其存储到附加参数所指向的位置
  • 额外的参数应该指向已经分配的对象,其类型由格式字符串中相应的格式说明符指定

需要以特定的格式的字符串

int format_operation1(void)
{

	struct S s = { 0 };

	//打开文件
	FILE* pf = fopen("data5.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//读文件
	fscanf(pf, "%f %c %d", &(s.f), &(s.c), &(s.n));
	printf("%f %c %d\n", s.f, s.c, s.n);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

注:格式应与文件中一样

根据输出结果,我们可以发现,原本文件中的字符串,被我们以 float char int 的格式分别读到了 f,c,n 三个变量中,也就是说我们将原本的字符串变成了不同格式的数据,在使用这个函数时,注意他的参数,只比 scanf 多了一个参数,也就是文件指针(流)

fprintf

  • 将格式化的数据写入流
  • 将由 format 指向的 C字符串写入流。如果 format 包含格式说明符(以%开头的子序列),则格式化format 之后的其他参数并将其插入到结果字符串中,以替换它们各自的说明符。
  • 在format 形参之后,函数期望至少与format 指定的一样多的附加参数。
int format_operation2(void)
{

	struct S s = { 1.2345f, 'a', 100 };

	//打开文件
	FILE* pf = fopen("data6.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//写文件
	fprintf(pf, "%f-%c-%d", s.f, s.c, s.n);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;

}

运行结果如下:

根据输出结果,我们可以发现,我们以结构体的格式,将其中 float char int 三种类型的数据写入了文件,在写入文件后,这些数据就失去了原本的格式,相当于变成了一条字符串,在使用的时候,他只比我们的 scanf 多了一个参数,也就是文件指针(流) 

五、二进制文件操作函数

fread

  • 从流中读取数据块
  • 从流中读取一个由 count 元素组成的数组,每个元素的大小为 size 字节,并将它们存储在 ptr 指定的内存块中
  • 流的位置指示器按读取的总字节数前进
  • 如果成功读取的总字节数为 (size*count)

参数

  • void * ptr:指向大小至少为(size*count)字节的内存块的指针,转换为 void* 
  • size_t size:要读取的每个元素的大小(以字节为单位)
  • size_t count:元素的数目,每个元素的大小为 size 字节
  • FILE * stream:指向指定输入流的 FILE 对象的指针(文件指针)

首先有个txt文件

int binary_operation1()
{
	//二进制的方式读取文件

		int arr[15] = { 0 };

		//写文件
		FILE* pf = fopen("data7.txt", "rb");
		if (pf == NULL)
		{
			perror("fopen");
			return 1;
		}

		//二进制的读文件
		fread(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);

		int i = 0;
		for (i = 0; i < 15; i++)
		{
			printf("%d ", arr[i]);//以二进制文件读取的所以是乱数
		}

		//关闭文件
		fclose(pf);
		pf = NULL;

		return 0;


}

运行结果如下

 结果和预期的完全不一样,这是因为是以二进制的方式读取,打印的时候却是以十进制的方式打印,这样就相当于给数据加密了,我们无法直观的看见我们读取了什么数据,但是我们确确实实是读取到了。那么如何读取到呢?下面会做出介绍

fwrite

  • 将数据块写入流
  • 将由 count 元素组成的数组 (每个元素的大小为 size 字节) 从 ptr 所指向的内存块写入流中的当前位置
  • 流的位置指示器按写入的总字节数前进
  • 在内部,该函数将 ptr 指向的块解释为 unsigned char 类型的 (size*count) 元素数组,并将它们顺序写入流,就像对每个字节调用 fputc 一样

参数:

  • void * ptr:指向大小至少为(size*count)字节的内存块的指针,转换为 void* 
  • size_t size:要写入的每个元素的大小(以字节为单位)
  • size_t count:元素的数目,每个元素的大小为 size 字节
  • FILE * stream:指向指定输入流的 FILE 对象的指针(文件指针)
int binary_operation2()
{
	//二进制的方式写进文件

	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };

	//写文件
	FILE* pf = fopen("data8.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//二进制的写文件
	fwrite(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;

}

运行结果如下:

同样,我们还是无法直观的看见我们存储了什么,这是因为记事本使用的是 UTF-8 码,和我们保存的二进制并不兼容,这从十进制转到二进制再用 UTF-8 码进行显示也就相当于对文本进行了一层加密,解铃还须系铃人,通过fread读取试一下

int binary_operation3()
{
	//二进制的方式读取文件

	int arr[10] = { 0 };

	//写文件
	FILE* pf = fopen("data8.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//二进制的读文件
	fread(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;

}

运行结果如下

这一次可以正确读取到数据了,也就是说fread 和 fwrite都不会影响数据的真实性,只是被加密了,无法直观看到。

总结:

fgetc:从文件中读取单个字符(char)

fputc:对文件写入单个字符(char)

fgets:从文件中读取一个字符串(string)

fputs:对文件写入一个字符串(string)

fscanf:将文件中的字符串转换为有格式的数据并且读取出来(format)

fprintf:将有格式的数据转换为字符串并且写入文件(format)

fread:将文件中的内容转换为二进制然后读取出来(binary)

fwrite:将数据转换为二进制然后写入文件(binary)

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

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

相关文章

【全网最全】《2024高教社杯/国赛》 C题 思路+代码+文献 蒙特卡洛+遗传算法 第一问 农作物的种植策略

​ 领取压缩包 问题 1&#xff1a;建模思路与方法 问题描述 我们需要为某乡村在 2024-2030 年间制定最优的农作物种植方案。考虑的因素包括农作物的销售量、种植成本、亩产量、销售价格、以及不同土地的适宜种植条件等。该问题分为两种情况&#xff1a;(1) 超过部分滞销&#…

【redis】本地windows五分钟快速安装redis

用处&#xff1a;本地自测&#xff0c;有时候公司redis环境不稳定&#xff0c;用自己的 1.下载&#xff0c;github下载一个解压缩在自己想要的位置 选择版本&#xff1a;Redis-7.4.0-Windows-x64-msys2-with-Service&#xff0c;zip GitHub - redis-windows/redis-windows: …

django学习入门系列之第十点《案例 用户管理》

文章目录 展示用户列表添加用户删除用户url中&#xff1f;的作用 往期回顾 展示用户列表 方向 展示用户列表 url函数 获取用户所有的信息基于HTML给他个渲染 views.py from django.shortcuts import render, HttpResponse, redirect# Create your views here.from app01.…

c++162 类的封装和访问

怎么样管理类管理对象 类如何定义对象 #include<iostream> using namespace std;//求圆的面积 class MyCirecle { public:double m_r;//属性 成员变量double m_s; public :double getR(){return m_r;}void setR(double r)//成员函数{m_r r;}double getS(){m_s 3.14…

CMU 10423 Generative AI:lec2

文章目录 1 概述2 部分摘录2.1 噪声信道模型&#xff08;Noisy Channel Models&#xff09;主要内容&#xff1a;公式解释&#xff1a;应用举例&#xff1a; 2.2 n-Gram模型1. 什么是n-Gram模型2. 早期的n-Gram模型3. Google n-Gram项目4. 模型规模与训练数据5. n-Gram模型的局…

EmguCV学习笔记 VB.Net 10.1 人脸检测 CascadeClassifier类

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

视觉语言模型(VLMs)知多少?

最近这几年&#xff0c;自然语言处理和计算机视觉这两大领域真是突飞猛进&#xff0c;让机器不仅能看懂文字&#xff0c;还能理解图片。这两个领域的结合&#xff0c;催生了视觉语言模型&#xff0c;也就是Vision language models (VLMs) &#xff0c;它们能同时处理视觉信息和…

单片机原理

一、单片机基础知识 1.单片机概念 将通用微型计算机基本功能部件集成在一块芯片上构成的一种专用微计算机系统&#xff08;嵌入式系统&#xff09;&#xff0c;用于解决小型被控对象的智能化问题&#xff08;SCM或MCU&#xff09;。 2.单片机组成 3.单片机命名规则 后缀 后缀…

ChatGPT付费创作系统V3.0.6独立版 WEB+H5+小程序端 (新增AI全网搜索+文档解析+豆包AI通道)安装部署教程

播播资源GPT付费体验系统最新版系统是一款基于ThinkPHP框架开发的AI问答小程序&#xff0c;是基于国外很火的ChatGPT进行开发的Ai智能问答小程序。这是一种基于人工智能技术的问答系统&#xff0c;可以实现智能回答用户提出的问题。相比传统的问答系统&#xff0c;ChatGPT可以更…

基于.NET6的WPF总结之MVVM

目录 1. DataContext数据上下文 2. Binding绑定源 2.1 绑定实体 2.2 绑定资源 2.3 ElementName属性指明另一个控件作为数据源 2.4 RelativeSource属性绑定一个相对的数据源 2.4.1 Self&#xff08;绑定自身控件&#xff09; 2.4.2 FindAncestor&#xff08;找上级&#…

vue3获取视频时长、码率、格式等视频详细信息

前言&#xff1a; 我们在上传视频需要视频的帧数等信息的时候&#xff0c;上传组件无法直接读取帧数等信息 方法&#xff1a;通过mediainfo.js来获取视频的帧率、总帧数和视频的总时长 mediainfo.js地址&#xff0c;想详细了解的可以去看看git地址&#xff1a;https://githu…

【C++ Primer Plus习题】11.3

问题: 解答: main.cpp #include <iostream> #include <cstdlib> #include <ctime> #include "vect.h"using namespace std; using namespace VECTOR;int main() {srand(time(0));double direction;Vector step;Vector result(0.0, 0.0);unsigned …

基于 BiLSTM+Attention 实现降雨预测多变量时序分类——明日是否降雨

前言 系列专栏:【深度学习&#xff1a;算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域&#xff0c;讨论了各种复杂的深度神经网络思想&#xff0c;如卷积神经网络、循环神经网络、生成对…

uniapp解决页面跳转时,含有base64的数据丢失问题

由于url长度的限制&#xff0c;base64数据过长可能导致数据丢失&#xff0c;以至于base64图片显示不出来或者格式错误。 解决办法&#xff1a; 跳转前进行base64编码&#xff1a;encodeURIComponent 接收数据时&#xff0c;对base64进行解码&#xff1a;decodeURIComponent

【2024数模国赛赛题思路公开】国赛D题思路丨附可运行代码丨无偿自提

2024年国赛D题解题思路 问题一 【题目】 投射一枚深弹&#xff0c;潜艇中心位置的深度定位没有误差&#xff0c;两个水平坐标定位均服从正态分布。分析投弹最大命中概率与投弹落点平面坐标及定深引信引爆深度之间的关系&#xff0c;并给出使得投弹命中概率最大的投弹方案&…

One-Shot Hierarchical Imitation Learning of Compound Visuomotor Tasks

发表时间&#xff1a;25 Oct 2018 论文链接&#xff1a;https://readpaper.com/pdf-annotate/note?pdfId4500198746683498497&noteId2453372035670907392 作者单位&#xff1a;Berkeley AI Research Motivation&#xff1a;我们考虑从执行任务的人类的单个视频中学习真…

ITK-重采样

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 什么是重采样 重采样&#xff08;Resampling&#xff09; 是一种用于图像处理的技术&#xff0c;主要应用于对图像进行尺寸调整、…

【专项刷题】— 栈

1、删除字符串中的所有相邻重复项 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 使用栈进行操作&#xff0c;每次入栈的时候和栈顶元素进行比对&#xff0c;如果相同的话就弹出栈顶元素也可以用数组来模拟栈进行操作代码&#xff1a; public String removeDuplica…

基于人工智能的交通标志识别系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 交通标志识别系统是自动驾驶和智能交通的重要组成部分&#xff0c;能够帮助车辆自动识别路边的交通标志并作出相应的决策。通过使用深…

C语言-数据结构 无向图普里姆Prim算法(邻接矩阵存储)

Prim算法使用了贪心的思想&#xff0c;在算法中使用了两个数组&#xff0c;这两个数组会非常巧妙的操作整个算法的灵魂过程 lowcost的功能&#xff1a; 1.帮助算法寻找到当前距离已完成的最小生成树集合的最小的边长&#xff08;找到新边&#xff09; 2.在整个过程中记录新结…