C/C++文件操作/IO流

news2024/12/23 4:22:35

学习任务:

⭐认识文件。⭐学习C语言中文件如何打开和关闭。⭐学习C语言中文件的读写方法(包括顺序读写和随机读写)。⭐学习C语言文件操作中如何判断文件读取结束。⭐简单了解FILE缓冲区。⭐认识流。⭐学习C++的IO流,包括标准IO流和文件IO流,即C++的文件操作。⭐学习stringstream。

学习流程:

先对C语言的文件操作进行学习,然后带着建立在C语言文件操作的基础和C++基础上学习C++IO流。

1、认识文件

程序文件和数据文件

直接点 - 磁盘上的文件,就是文件。从文件功能的角度上,文件分有数据文件和程序文件。

程序文件包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程(windows环境后缀为.exe)。

数据文件的文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。

文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。文件名包含3部分:文件路径+文件名主干+文件后缀。

例如: c:\C++_code\test.txt

2、文件的打开和关闭

2.1 文件指针

在C语言的文件操作中,需要使用文件指针来对硬盘上的文件进行操作。每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名为FILE。

以下是FILE结构体的成员变量,不同编译器或许有不同的变量,但是大同小异。除此之外,FILE中会保存缓冲区、文件描述符等等。

//FILE
struct _iobuf {
	char* _ptr;
	int _cnt;
	char* _base;
	int _flag;
	int _file;
	int _charbuf;
	int _bufsiz;
	char* _tmpfname;
};
typedef struct _iobuf FILE;

每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息。

FILE* f;//文件指针变量

定义f是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件,即通过文件指针变量能够找到与它关联的文件,就如上图一样,f指向了文件信息区。

2.2 文件的打开与关闭操作

对一个文件进行读写操作之前先打开该文件,操作完后需要关闭文件。在C语言中,使用fopen打开文件,使用fclose关闭文件。

//打开文件
FILE * fopen ( const char * filename, const char * mode );
参数:
filename:需要打开的文件的名字+路径(默认在当前文件路径中)
mode:打开文件的方式
返回值:返回一个文件指针


//关闭文件
int fclose ( FILE * stream );
参数:文件指针,即需要关闭的那个文件的文件指针
返回值:成功返回0

文件的打开方式

文件使用方式含义如果指定文件不存在
“r”(只读)为了输入数据,打开一个已经存在的文本文件出错
“w”(只写)为了输出数据,打开一个文本文件建立一个新的文件
“a”(追加)向文本文件尾添加数据建立一个新的文件
“rb”(只读)为了输入数据,打开一个二进制文件出错
“wb”(只写)为了输出数据,打开一个二进制文件建立一个新的文件
“ab”(追加)向一个二进制文件尾添加数据出错
“r+”(读写)为了读和写,打开一个文本文件出错
“w+”(读写)为了读和写,建议一个新的文件建立一个新的文件
“a+”(读写)打开一个文件,在文件尾进行读写建立一个新的文件
“rb+”(读写)为了读和写打开一个二进制文件出错
“wb+”(读写)为了读和写,新建一个新的二进制文件建立一个新的文件
“ab+”(读写)打开一个二进制文件,在文件尾进行读和写建立一个新的文件

代码演示

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");//只读方式打开
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//读文件操作
	//.....

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

3、文件的顺序读写

对于文件的顺序读写,有以下函数需要学习去使用:

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

3.1 代码演示

3.1.1 fgetc和fputc函数

fputc函数+只写操作,写字符进去文件中,文件路径默认当前路径

int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "w");//只写方式打开
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//写文件
	char i = 0;
	for (i = 'a'; i <= 'z'; ++i)
	{
		fputc(i, pf);
	}


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

fgetc函数+只读操作:

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	//读文件
	int ch = 0;
	while ((ch = fgetc(pf)) != EOF)
	{
		printf("%c ", ch);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

 3.1.2 fgets和fputs函数

fputs函数+只写操作

//写一行数据
int main()
{
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}

	//写一行数据
	fputs("hello bit\n", pf);
	fputs("hello bit\n", pf);


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

	return 0;
}

fgets函数+只读操作

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		//printf("%s\n", strerror(errno));
		perror("fopen");
		return 1;
	}

	//读一行数据
	char arr[20];
	fgets(arr, 20, pf);
	printf("%s\n", arr);

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

	return 0;
}

 3.1.3 fsacnf和fprintf函数

fprintf函数+只写操作

struct S
{
	char arr[10];
	int age;
	float score;
};


int main()
{
	struct S s = { "zhangsan", 25, 50.5f };

	FILE*pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//
	fprintf(pf, "%s %d %f", s.arr, s.age, s.score);

	fclose(pf);
	pf = NULL;
	return 0;
}

 fscanf函数+只读操作

int main()
{
	struct S s = {0};

	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//将pf中的数据写到结构体对象s中
	fscanf(pf, "%s %d %f", s.arr, &(s.age), &(s.score));
	//打印
	//printf("%s %d %f\n", s.arr, s.age, s.score);
	fprintf(stdout, "%s %d %f\n", s.arr, s.age, s.score);

	fclose(pf);
	pf = NULL;
	return 0;
}

对于以上三对接口,都适用于所有输入或输出流,简单来说,不仅仅适用于文件流的读写,还可以是标准输入输出流,使用方法就是将文件指针改成以下三种流的名字即可。

任何一个C程序,只要运行起来就会默认打开3个流:

FILE* stdin - 标准输入流(键盘)

FILE* stdout - 标准输出流(屏幕)

FILE* stderr - 标准错误流(屏幕)

3.1.4 fread和fwrite函数

fread和fwrite是以二进制的形式进行读写,即保存在文件的数据是二进制的形式保存的。

fwrite函数+二进制只写操作

struct S
{
	char arr[10];
	int age;
	float score;
};


int main()
{
	struct S s = { "zhangsan", 25, 50.5f };
	//以二进制的形式写到文件中
	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;
}

fread函数+二进制只读操作

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);
	printf("%s %d %f\n", s.arr, s.age, s.score);

	fclose(pf);
	pf = NULL;
	return 0;
}

3.2 对比函数 

对比以下函数

scanf/fscanf/sscanf

 
printf/fprintf/sprintf

从上面的示例代码中我们已经知道,前两组的区别是:

scanf是针对标准输入格式化输入语句

printf是针对标准输出格式化输出语句

fscanf是针对所有输入流的格式化输入语句

fprintf是针对所有输出流的格式化输出语句

而对于sscanf和sprintf

sscanf是从字符串中读取格式化数据

 sprintf是将格式化数据写入字符串

struct S
{
	char arr[10];
	int age;
	float score;
};

int main()
{
	struct S s = { "zhangsan", 20, 55.5f };
	struct S tmp = { 0 };
	char buf[100] = { 0 };
	//把s中的格式化数据转化成字符串放到buf中
	sprintf(buf, "%s %d %f", s.arr, s.age, s.score);

	//"zhangsan 20 55.500000";
	printf("字符串:%s\n", buf);

	//从字符串buf中获取一个格式化的数据到tmp中
	sscanf(buf, "%s %d %f", tmp.arr, &(tmp.age), &(tmp.score));
	printf("格式化:%s %d %f\n", tmp.arr, tmp.age, tmp.score);
	return 0;
}

这一对函数跟序列化与反序列化很相似。

文件的随机读写

文件的随机读写,有三个函数提供服务:fseek、ftell和rewind。

fseek函数:

int fseek ( FILE * stream, long int offset, int origin );
函数功能:根据文件指针的位置和偏移量来定位文件指针。
参数:
stream:文件指针
offset:偏移量
origin:从文件指针的位置

 origin参数:

SEEK_SET:文件的开头

SEEK_CUR:文件指针当前位置

SEEK_END:文件的末尾

#include <stdio.h>
int main()
{
	FILE* pFile;
	pFile = fopen("example.txt", "wb");
	fputs("This is an apple.", pFile);
	fseek(pFile, 9, SEEK_SET);
	fputs(" sam", pFile);
	fclose(pFile);
	return 0;
}

ftell函数

long int ftell ( FILE * stream );
函数功能:返回文件指针相对于起始位置的偏移量。

rewind函数

void rewind ( FILE * stream );
函数功能:让文件指针的位置回到文件的起始位置。

文本文件和二进制文件

根据数据的组织形式,数据文件被称为文本文件或者二进制文件。

数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。

如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。

文件读取结束的判断

feof函数

feof函数用来判断文件读取结束的原因是什么?是读取失败结束,还是遇到文件尾结束。

1. 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets)。

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

文件缓冲区

ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。

C++IO流 

流是什么

“流”即是流动的意思,是物质从一处向另一处流动的过程,是对一种有序连续且具有方向性的数据( 其单位可以是bit,byte,packet )的抽象描述。

C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存向外部输出设备(显示器)输出的过程。这种输入输出的过程被形象的比喻为“流”。它的特性是:有序连续、具有方向性。为了实现这种流动,C++定义了I/O标准类库,这些每个类都称为流/流类,用以完成某方面的功能。

C++系统实现了一个庞大的类库,其中ios为基类,其他类都是直接或间接派生自ios类。

 C++标准IO流

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

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

相关文章

【CMake】给一个库添加用法需求(Usage Requirements)

3. 给一个库添加用法需求&#xff08;Usage Requirements&#xff09; 1. usage requirements 目标参数的用法要求&#xff08;不知道有没有更好的翻译方式&#xff09;可以更好地控制库或可执行的链接&#xff0c;并包括行&#xff0c;同时还可以更好地控制CMAKE内部目标的传…

【哈士奇赠书活动 - 17期】-〖uni-app跨平台开发与应用从入门到实践〗

文章目录 ❤️‍&#x1f525; 赠书活动 - 《uni-app跨平台开发与应用从入门到实践》❤️‍&#x1f525; 编辑推荐❤️‍&#x1f525; 抽奖方式与截止时间❤️‍&#x1f525; 赠书活动 → 获奖名单 ❤️‍&#x1f525; 赠书活动 - 《uni-app跨平台开发与应用从入门到实践》…

日志技术-Logback

一. 日志是什么&#xff1a; 输出语句的弊端&#xff1a;它只能在控制台展示&#xff0c;它不能记录在本地文件当中。 日志可以将程序运行过程中的信息直接记录在文件里面&#xff0c;做永久存储。 性能较好&#xff0c;简单来说就是运行的速度会比较快。 二. 日志技术体系、L…

3_docker应用部署:MySQL-Tomcat-Nginx-Redis

Docker 应用部署 一、部署MySQL 案例需求&#xff1a;在Docker容器中部署MySQL&#xff0c;并通过外部mysql客户端操作MySQL Server。 分析&#xff1a; 容器内的网络服务和外部机器不能直接通信 外部机器和宿主机可以直接通信 宿主机和容器可以直接通信 当容器中的网络服…

iOS 17 开放侧载,微信双开要来了?

关于苹果北京时间 6 月 6 日召开的 WWDC23 全球开发者大会&#xff0c;外媒彭博记者 Mark Gurman 带来了最新消息。 大致更新概览 他认为&#xff0c;本次 WWDC23 大会将会主要推出这几款产品和软件&#xff1a;iOS 17、iPadOS 17、macOS 14、watchOS 10、新的 MacBooks 、混…

文件上传下载系列——如何实现文件秒传

文章目录 &#x1f383;简介&#xff1a; &#x1f47b;核心思想&#xff1a; MD5是什么&#xff1f; 实现步骤&#xff1a; &#x1f384;实操&#xff1a; 1、java生成文件MD5码 2、javascript生成文件MD5码 ⛳️基于秒传的分片上传下载 上传&#xff1a; 下载&…

Afkayas.1(★)

软件运行 要输入正确的Name和Serial 查壳 一个VB程序&#xff0c;没有加壳 载入OD 直接开搜索字符串。 这里看到了错误的提示&#xff0c;“You Get It”应该就是成功的字符串了。 前面的“AKA-”应该是在什么时候拼接的字符串 去成功的字符串附近看看 这个字符串上面…

LVS负载均衡群集——DR模式

一、LVS-DR集群介绍 LVS-DR&#xff08;Linux Virtual Server Director Server&#xff09;工作模式&#xff0c;是生产环境中最常用的一 种工作模式。 1、LVS-DR 工作原理 LVS-DR 模式&#xff0c;Director Server 作为群集的访问入口&#xff0c;不作为网关使用&#xff0…

第九章 子查询

文章目录 前言一、.需求分析与问题解决1 、实际问题2 、子查询的基本使用3 、子查询的分类 二、单行子查询1、单行比较操作符2、代码示例3、 HAVING 中的子查询4、CASE中的子查询5、 子查询中的空值问题6、非法使用子查询 三、多行子查询1、 多行比较操作符2、代码示例3 、空值…

客快物流大数据项目(一百一十八):配置中心 Spring Cloud Config

文章目录 配置中心 Spring Cloud Config 一、​​​​​​​Config 简介

STM32-HAL-SPI-W25Q128FV简单读写测试(2)

文章目录 一、Flash的基本读写操作1.1 向芯片中的某个地址&#xff08;addr:0x02&#xff09;连续写入不定长的数据并读取代码示例读写流程分析函数分析 1.2 向芯片中的某个地址&#xff08;addr:0x00&#xff09;写入一个数值代码示例&#xff1a;读写流程分析 具体的配置接上…

react native ios 添加启动页 xcode14

最近更新xcode&#xff0c;有些配置有些不同&#xff0c;网上查的方法都是过时的&#xff0c;导致配了一段时间卡在这里&#xff0c;最后访问官网才弄好了&#xff0c;所以以后解决问题的办法先看官网再查其他各路神仙的办法。 官网的步骤&#xff1a;https://github.com/crazy…

MAC 查看已装载的卷宗

查看卷宗目录命令 ls /Volumes网络卷宗&#xff1a;本机、系统报告。 参考资料&#xff1a;https://blog.csdn.net/qq_41731201/article/details/125407204

建筑行业如何进行高效管理文件?

建筑设计行业在日常办公中会产出大量文件&#xff0c;如设计图纸协作商议&#xff0c;项目资料等&#xff0c;建筑行业该如何高效管理文件呢&#xff1f; 建筑设计行业团队可能遇到的文件管理问题&#xff1a; 1&#xff0c;设计图纸一般较大&#xff0c;来回传输不仅麻烦&…

【矩阵快速幂 | 斐波那契数列 | 矩阵加速】

文章目录 基础知识1. 矩阵结构2. 重载 * 运算符3. 矩阵快速幂 例题1&#xff1a; 矩阵幂求和例题2&#xff1a; 矩阵快速幂例题3&#xff1a; 斐波那契数列例题4&#xff1a; 矩阵加速例题5&#xff1a; 广义斐波那契例题6&#xff1a; 斐波那契公约数例题7&#xff1a; 这个勇…

设计模式——设计模式介绍和单例设计模式

目录 一、设计模式概述和分类 1.1 设计模式介绍 1.2 设计模式分类 二、创建型设计模式-单例模式 2.1 介绍 2.2 八种单例模式的创建方式 2.2.1 饿汉式&#xff08;静态常量&#xff09; 2.2.2 饿汉式&#xff08;静态代码块&#xff09; 2.2.3 懒汉式&#xff08;线程…

TCP/IP协议基础

1.TCP/IP模型的分层 网络接口层&#xff08;Network Interface Layer&#xff09;&#xff1a;&#xff08;数据链路层&#xff09; 功能&#xff1a; ①将数据帧发送到物理网络&#xff0c;并从物理网络接收数据帧。 ②处理硬件地址&#xff0c;如MAC地址。 主要协议&#xff…

[独家]自动播放K线图训练盘感能力!股票量化分析工具QTYX-V2.3.5

K线量价的重要性 K线图对炒股的朋友来说太熟悉不过了&#xff0c;每一根K线包含了开盘价、收盘价、最高价和最低价这四个价位信息&#xff0c;分别用红和绿两种颜色来表示上涨或下跌&#xff0c;反映了单位时间周期内价格变动的情况。 不过K线的功效可不仅仅用来记录价格的变动…

Linux信号:信号 信号集 信号集函数

1. 信号的概念 Linux进程间通信的方式之一。信号也称为“软件中断”。 信号特点&#xff1a; 简单&#xff1b;携带信息有限&#xff1b;满足特定条件才发送信号&#xff1b;可进行用户空间和内核空间进程的交互&#xff1b; 信号4要素&#xff1a; &#xff08;1&#xf…

根据Java的TreeMap源码的原理编写C++红黑树删除操作

&#xff08;一&#xff09;了解二叉搜索树的删除操作 删除操作总结&#xff1a; ******普通结点删除&#xff1a;******* ①删除叶结点 ②删除只有1个子结点的结点 >>如果被删除结点的左子树为空&#xff0c;则令其右子树子承父业代替其位置即可 >>如果被删除结点…