C++练级计划-> 《IO流》iostream fstream sstream详解

发布于:2024-11-29 ⋅ 阅读:(30) ⋅ 点赞:(0)

如果是想全部过一遍就看完,如果想具体的了解某一个请点目录。因为有三种流的使用可能内容多 

目录

流是什么?

C++IO流(iostream)

io流的注意事项

cin和cout为什么能直接识别出类型和数据

fstream

fstream的使用方法: 

1.以二进制打开文件并写入和读取

2.以文本打开文件并读取或写入

3.用>> << 重载符号读取或写入

sstream

stringstream:

1.提取stringstream流中的数据

2.删除stringstream流中的数据

3.stringstream的常见用法:

4.stringstream能使用的oj题:


流是什么?

首先io流就是iostream,全称 in out stream,输入输出流。

怎么理解流呢?

把它想成一个数据结构(抽象的),里面流动的(存的)是字节流,或者字符流。

字节流就是二进制数据,字符流就是字符数据。二进制数据主要是图片视频等,字符数据就是一个文档全是字的。

 所以流就可以想象成从一个地方拿数据,然后供给另一个地方,南水北调,南边的水,供给北方

这里中间传输的过程就是流。南水放入,北方取出加工使用。

C++IO流

这里的ios_base就是大基类(父类),里面保存的就是每个流都应该有的功能,ios是继承自ios_base的一个类,但是不只是只有一个ios,这里的ios类旨在处理char单字符,而对于wchar这样的宽字符它是无法处理的,所以还有另外一个wios类专门用于处理wchar。

ios就是后面的所有类的基类(父类)

iostream(经常用于屏幕打印数据)

in out stream

cin:流提取(istream),用于从io流中提取数据,比如说读文件、获取键盘的信息等

cout:流插入(ostream),将数据放入io流中,供其他程序提取。比如写文件(将数据写到屏幕上就是打印)

cerr:也是流插入(ostream)。某处出错时,将错误数据放入io流。一般在屏幕打印

clog:也是流插入(ostream)。进行日志的输出,屏幕打印

fstream(文件)

file stream:顾名思义这个流是给文件使用的。

sstream(字符串)

string stream:这个则是给字符串使用的。

io流的注意事项

注意:1.cin是以空格和换行为分隔符的

在使用cin时如果我们在输入时,数据中间加了空格,有人要提取数据,提取到的是空格前的数据。下一次有人又来提取时,这时是先把之前空格后的数据先给出去。

#include <iostream>
using namespace std;
int main()
{
	int a = 0, b = 0;
	cin >> a; //输入:10 20
	cout << a << endl;
	cin >> b; //直接从输入缓冲区提取
	cout << b << endl;
	return 0;
}

如上代码我们输入时输入 10 20,第二次cin时根本不会停下来等你输入数据,而是直接把20给b。然后输出。所以在使用cin时要注意空格的使用

2.输入类型和要输出到的类型必须一致

3.getline函数:用于输入时只把换行当做分隔符。

这个函数只能用于字符串,所以1.中输入数字的情况用不了

#include <iostream>
#include <string>
using namespace std;
int main()
{
	string s;
    //cin>>s;          //cin输入,最终只输出hello
	getline(cin, s);   //输入:"hello world"
	cout << s << endl; //输出:"hello world"
	return 0;
}

cin和cout为什么能直接识别出类型和数据

cin重载的>>运算符

 cout重载的<<运算符

在C++标准库中对于内置类型的输入和输出已经全部重载,所以cin和cout能识别类型是这个原因。对于自定义类型而言: class类,在定义类时如果需要使用>> 和 << 需要自己手写接口实现。实现方法对应自己类的功能。

fstream

fstream有三个类和一个filebuf缓冲区

文件流的三个类:

对应操作场景
ofstream 只写
ifstream 只读
fstream 读+写

 文件的打开方式:

打开方式 功能
in 以读的方式打开文件
out 以写的方式打开文件
binary 以二进制方式对文件进行操作
ate 输出位置从文件的末尾开始
app 以追加的方式对文件进行写入
trunc 先将文件内容清空再打开文件

文件流的函数:

成员函数 功能
put 插入一个字符到文件
write 插入一段字符到文件
get 从文件提取字符
read 从文件提取多个字符
tellg 获取当前字符在文件当中的位置
seekg 设置对文件进行操作的位置
>>运算符重载 将数据形象地以“流”的形式进行输入
<<运算符重载 将数据形象地以“流”的形式进行输出

fstream的使用方法: 

1.以二进制打开文件并写入和读取

写入文件:

#include <iostream>
#include<fstream>
using namespace std;
void ofsteam_test_binary()
{
	//为什么o是写入,output是输出的意思,意味着我们要从流中输出给文件
	ofstream ofs;
	ofs.open("binoptest.txt", ofstream::binary | ofstream::out);//以二进制写的方式打开文件
	char str[] = "中国无敌";
	ofs.write(str, strlen(str));
	ofs.put('!');//put是单字符的写入
	//使用任何类时都要记得close
	ofs.close();
}
int main()
{
	ofsteam_test_binary();
	return 0;
}

解释:我们创建一个ofstream对象,用二进制out的方式打开文件binoptest.txt,为什么out是输出这里我们要把视角看成是流的视角:流把数据output进了binoptest.txt,所以ofstream是输出流。

结果:

1.在当前目录生成一个binoptest.txt文件 

2.文件内容为:

读取文件:

void ifstream_test_binary()
{
	ifstream ifs;
	ifs.open("binoptest.txt", std::ios::binary | std::ios::in);
	char str[32];
	//计算文档内容的大小
	ifs.seekg(0,std::ios::end);
	int len = ifs.tellg();
	ifs.seekg(0,std::ios::beg);
	//读取文件放入str
	ifs.read(str, len);
	ifs.close();
	//字符串末尾置为0
	str[len] = '\0';
	printf("%s", str);
}

解释:创建ifstream对象,打开文件创建str储存读取出来的数据。

注意:计算文档大小没有什么size函数但是可以用下面的代码

//计算文档内容的大小
	ifs.seekg(0,std::ios::end);
	int len = ifs.tellg();
	ifs.seekg(0,std::ios::beg);

seekg用来定位读指针,第一个参数是偏移量,代表从哪里开始定位,第二个参数是根据偏移量后从哪里开始end代表结尾,beg代表开始,我们一开始就把定位移到了最后,然后tellg是用来计算当前读指针的偏移量的(从头开始计算),然后再让读指针回到beg开始,就完成了一次文档计数

结果 :

2.以文本打开文件并读取或写入

写入文件:

void ofstream_test_text()
{
	ofstream ofs;
	//默认的output方式是文本的
	ofs.open("text.txt");
	char str[] = "中国无敌";
	ofs.write(str, strlen(str));
	ofs.put('!');//put是单字符的写入
	//使用任何类时都要记得close
	ofs.close();
}

 和二进制的区别只是,在open时二进制文件和文本文件不同,open默认打开文件是以文本方式打开的,如果要使用二进制打开就需要设置打开方式。

结果:

读取文件:

void ifstream_test_text()
{
	ifstream ifs;
	ifs.open("text.txt");
	char str[32];
	//计算文档内容的大小
	ifs.seekg(0, std::ios::end);
	int len = ifs.tellg();
	ifs.seekg(0, std::ios::beg);
	//读取文件放入str
	ifs.read(str, len);
	ifs.close();
	//字符串末尾置为0
	str[len] = '\0';
	printf("%s", str);
}

和写入文件一样:和二进制的区别就是open的打开方式。

结果: 

注意:除了指定二进制外,我们还可以指定读和写:默认的情况下:ifstream打开文件是以读的方式,ofstream打开文件是以写的方式打开,而fstream是以读加写的方式打开。

3.用>> << 重载符号读取或写入

写入文件:

void writefile()
{
	ofstream ofs;
	ofs.open("file.text");
	string s = "中国无敌!";
	ofs << s;
}

结果:

读取文件:

void readfile()
{
	ifstream ifs;
	ifs.open("file.text");
	string s;
	ifs >> s;
	cout << s;
	ifs.close();
}

结果:

 

可以看出如果以重载符来写入或者读取时使用方法和cout 和 cin 类似区别只是在于 cout 和 cin的默认设备分别是屏幕和键盘,而我们用文件流的写入和读取,可以自己选择文件。键盘和屏幕也是文件。 

sstream

对应操作场景
ostringstream 输出操作
istringstream 输入操作
stringstream 输入操作+输出操作

介绍一下:sstream 全称 stringstream 字符串流:顾名思义一定和字符串有关,而这里的stringstream就是用来解决字符串转换的问题,在c语言时要进行字符串转换就要用到itoa等函数,在c++中用stringstream就可以完成 

stringstream:

因为用法类似所以这里只介绍stringstream,stringstream是在底层维护了一个字符串,在这个字符串中完成对应的操作,放进这个字符串的数据默认就变成字符了。

1.提取stringstream流中的数据

有两种从流中提取数据的方法:

    s.str(""); //将stringstream底层管理的string对象设置为""。
	s.clear(); //将上次转换状态清空掉

1.使用>>从流中提取

    int a = 10;
	string sa;
	stringstream s;
	s << a; //将int类型的a放入输入流
	s >> sa; //从s中抽取前面插入的int类型的值,赋值给string类型(方式一)
	cout << sa << endl;

2.使用.str()函数的方式提取

    double b = 3.14;
	s << b;
	sa = s.str(); //获取stringstream中管理的string类型(方式二)
	cout << sa << endl;

二者没什么差别>>是将stringstream中的内容通过复制的方式给出,而 .str()是通过 返回一个字符串的方式然后在赋值给出。

2.删除stringstream流中的数据
    s.str(""); //将stringstream底层管理的string对象设置为""。
	s.clear(); //将上次转换状态清空掉

上面的代码,首先将stringstream中的字符串给变为空字符串,然后用clear函数将状态清空。关于这个状态又是一个知识点:

stringstream底层在一次转换完成后会把标志位记成badbit这时代表的是流不可转换数据,使用clear后变成goodbit流才可转换。但是clear只是更改标记位而不会对内置的字符串进行更改所以这时需要将str置为空。

3.stringstream的常见用法:

1.将数据转换为字符类型

    int a = 10;
	string sa;
	stringstream s;
	s << a; //将int类型的a放入输入流
	s >> sa; //从s中抽取前面插入的int类型的值,赋值给string类型(方式一)
	cout << sa << endl;

2.字符串的拼接

#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main()
{
	string rets;
	stringstream s;
	s << "2021" << "dragon"; //将多个字符串放入stringstream中
	s >> rets; //方式一获取
	cout << rets << endl;
	s.str(""); //将stringstream底层管理的string对象设置为空字符串
	s.clear(); //将上次转换状态清空掉
	s << "Thanks" << " " << "for" << " " << "reading"; //将多个字符串放入stringstream中
	rets = s.str(); //方式二获取
	cout << rets << endl;
	return 0;
}
4.stringstream能使用的面试题:

1.统计字符串的个数

输入:“hello world c plus plus”
输出:5

#include <iostream>
#include <sstream>
#include <string>
 
using namespace std;
 
int main() {
	string str = "hello world c plus plus";
	int count = 0;
	stringstream ss(str);
	string word;
	while (ss >> word)
		count++;
	cout << count << endl;
	return 0;
}

很简单因为使用 >> 符号是以空格或者换行为分割符的,所以只要统计总共有几次输入进流中即可。 

2.反转字符串中的单词

class Solution {
public:
    string reverseWords(string s) 
    {
         string res,temp;
         stringstream ss(s);
         while(ss>>temp)
         {
            cout<<temp<<endl;
            res = temp + " " + res;
         }
         if(!res.empty())
         {
            res.pop_back();
         }
         return res;
    }
};

这题也很简单,将s 传入 ss的构造函数中,这时ss的底层里保存的就是s。此时通过>>流提取符号放入temp中,将数据类似头插的方法将temp放到res前面最后再把最后的空格删除。从这里也可以看出stringstream的>> 流插入符号是从字符串头的位置开始插入的,所以才能让temp中每次只出现一个字符串。