C++:C++的IO流

目录

一.C++标准IO流

1.operator bool

二.C++文件IO流

1.文件读取 ifstream

 (1)ifstream继承istream

(2)ifstream 构造函数 

 (3)ifstream,get读取整个文件

(4)>> 读取文件

2.文件输入 ofstream

(1)ofstream继承ostream

 (2)ofstream 构造函数 

(3)拷贝文件  ifstream 搭配 ofstream

3.二进制读写

4.文本读写

注意!!!:流提取>> 读取时按空格或换行读取

三.stringstream

1.用途:将 整形/自定义类型 转字符串

2.功能使用

(1)将数值类型数据格式化为字符串。

真正用法:自定义类型转字符串

字符串 转 自定义类型


C++:C++的IO流_第1张图片

箭头是子类继承,例如istream和ostream都继承ios,stream和ostream都是ios 子类;文件读写的ifstream继承istream,ofstream继承ostream。

注意:他们用法相同,只是去向不同:istream去向是控制台;fstream去向是文件;sstringstream去向是string对象

一.C++标准IO

while (scanf("%s", buff) != EOF)如何终止?

答:ctrl z+换行 是规定,ctrl c 是发送信号杀死进程(一般不建议ctrl c)。

int main()
{
	string str;
	while (cin >> str) // operator>>(cin, str)
	{
		cout << str << endl;
	}

	char buff[128];
	while (scanf("%s", buff) != EOF)
	{
	printf("%s\n", buff);
	}

	return 0;
}

C++:C++的IO流_第2张图片

 cin >> str 和 scanf("%s", buff) 自定义类型无法做真假逻辑判断,那他们在while循环中是如何判断返回值的?——用operator bool

1.operator bool

C++:C++的IO流_第3张图片

 operator bool:本质是为了支持自定义类型对象转换成bool类型,转换逻辑是自己设置的。(operator int 就是把自定义类型对象转换成int类型)

解释下面:operator bool()  这里是把Date对象转换成bool,返回值就是bool类型

    operator bool()
	{
		// 这里是随意写的,假设输入_year为0,则结束
		if (_year < 1)
			return false;
		else
			return true;
	}

	Date d2 = { 2022, 10, 11 };
    bool ret2 = d2;    支持自定义类型对象转换成bool类型
    cout << ret2 << endl;    打印结果:1(true)

istream类型对象转换为逻辑条件判断值
实际上我们看到使用while(cin>>i)去流中提取对象数据时,调用的是operator>>,返回值是
istream类型的对象,那么这里可以做逻辑条件值,源自于istream的对象又调用了operator
bool,operator bool调用时如果接收流失败,或者有结束标志,则返回false。

#include
#include
#include
#include
using namespace std;
class Date
{
	friend ostream& operator << (ostream& out, const Date& d);
	friend istream& operator >> (istream& in, Date& d);
public:
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}

	// 支持Date对象转换成bool
	operator bool()
	{
		// 这里是随意写的,假设输入_year为0,则结束
		if (_year < 1)
			return false;
		else
			return true;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1 = -1;
	Date d2 = { 2022, 10, 11 };

	bool ret1 = d1;    支持自定义类型对象转换成bool类型
	bool ret2 = d2;    支持自定义类型对象转换成bool类型

	cout << ret1 << endl;    打印结果:0(false)
	cout << ret2 << endl;    打印结果:1(true)

	if (d1) 这里本质上也是调用了operator bool,d1的Date类型转成了bool类型去做判断
	{
	}

	return 0;
}

二.C++文件IO

C++:C++的IO流_第4张图片

1.文件读取 ifstream

 (1)ifstream继承istream

C++:C++的IO流_第5张图片

C++:C++的IO流_第6张图片

 C++:C++的IO流_第7张图片

operator>>使用

char str[256];
ifstream ifs("test.cpp");
ifs>>str;     把文件test.cpp"内容读到str中

(2)ifstream 构造函数 

C++:C++的IO流_第8张图片

 ①ifstream()

先创建一个无参的ifstream对象,再open打开响应文件。

②explicit ifstream (const char* filename, ios_base::openmode mode = ios_base::in);

直接传参:filename:文件名称。mode:打开方式,可以不传。(把filename中内容读取到ifstream对象中)

C++:C++的IO流_第9张图片

input从头开始读,output输出不是给ifstream用的,binary 打开图片视频等,at end 追加写,

 (3)ifstream,get读取整个文件

get()每次读一个字符

#include
#include
using namespace std;

int main()
{
	ifstream ifs("Test.cpp");
	while (ifs)
	{
		char ch = ifs.get();
		cout << ch;
	}
	return 0;
}

C++:C++的IO流_第10张图片

(4)>> 读取文件

>> 自动过滤空格和换行: >>认为空格/换行只是一个间隔,会自动忽略

#include
#include
using namespace std;

int main()
{
	ifstream ifs("Test.cpp");
	char ch;
	while (ifs>>ch)
	{
		cout << ch;
	}
	return 0;
}

2.文件输入 ofstream

(1)ofstream继承ostream

C++:C++的IO流_第11张图片

 C++:C++的IO流_第12张图片

  operator<<使用

char str[256]="hello";
ofstream ofs("Copy.cpp");
ofs<

 (2)ofstream 构造函数 

C++:C++的IO流_第13张图片

①ofstream()

先创建一个无参的ofstream对象,再open打开响应文件。

②explicit ifstream (const char* filename, ios_base::openmode mode = ios_base::in);

直接传参:filename:文件名称。mode:打开方式,可以不传。(把filename中内容读取到ifstream对象中)

(3)拷贝文件  ifstream 搭配 ofstream

ofstream 向Copy.cpp文件中输入

C++:C++的IO流_第14张图片

3.二进制读写

注意:二进制读写只能用数组,不能string,string是指针,进程A写入,进程B读取string时就是野指针;文本读写可以用string,WriteText 中调的流插入 ofs << info._address << endl; 调用了string的operator<<重载


#include
#include
using namespace std;
struct ServerInfo
{
	char _address[256]; 
这里只能用数组,不能string,string是指针,进程A写入,进程B读取string时就是野指针
	//string _address;
	int _port;
};

struct ConfigManager
{
public:
	ConfigManager(const char* filename)
		:_filename(filename)
	{}

	void WriteBin(const ServerInfo& info)
	{
		//  1 2 4 8 16
		ofstream ofs(_filename, ios_base::out | ios_base::binary);  打开一个文件
		ofs.write((const char*)&info, sizeof(info));    向该文件写入 info的内容
	}

	void ReadBin(ServerInfo& info)
	{   把_filename文件读入ifs中,read把该文件内容读到info中去
		ifstream ifs(_filename, ios_base::in | ios_base::binary);
		ifs.read((char*)&info, sizeof(info));
	}
private:
	string _filename; // 配置文件
};
int main()
{
	ServerInfo winfo = { "https://legacy.cplusplus.com/reference/ios/ios/eof/", 80 };

二进制写:
	ConfigManager cf_bin("test.bin");   打开文件test.bin即可看到
	cf_bin.WriteBin(winfo); 
    因为是二进制写入,80整形被一个一个字节读到文件中就显示不出来	

二进制读:
	ServerInfo rbinfo;
	cf_bin.ReadBin(rbinfo);
	cout << rbinfo._address << "  " << rbinfo._port << "  ";
	
	return 0;
}

test.bin文件:(因为是二进制写入,80整形被一个一个字节读到文件中就显示不出来)

 把test.bin文件中二进制的内容再二进制读出来的结果:

4.文本读写

文本读写:转成字符串

注意:二进制读写只能用数组,不能string,string是指针,进程A写入,进程B读取string时就是野指针;文本读写可以用string,WriteText 中调的流插入 ofs << info._address << endl; 调用了string的operator<<重载

class Date
{
	friend ostream& operator << (ostream& out, const Date& d);
	friend istream& operator >> (istream& in, Date& d);
public:
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}

	// 支持Date对象转换成bool
	operator bool()
	{
		// 这里是随意写的,假设输入_year为0,则结束
		if (_year < 1)
			return false;
		else
			return true;
	}
private:
	int _year;
	int _month;
	int _day;
};

istream& operator >> (istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

ostream& operator << (ostream& out, const Date& d)
{
	out << d._year << " " << d._month << " " << d._day;
	return out;
}
——————————————————————————————————————————————————————下面是重点内容
struct ServerInfo
{
	string _address;
	int _port;

	Date _d;
};

struct ConfigManager
{
public:
	ConfigManager(const char* filename)
		:_filename(filename)
	{}

	// 文本读写
	void WriteText(const ServerInfo& info)
	{
		//  1 2 4 8 16
		ofstream ofs(_filename);
		ofs << info._address << endl;    调用了string的operator<<重载
		ofs << info._port << endl;       底层会把int转成字符串再读取到ofs文件中
		ofs << info._d << endl;          调用了Date友元的operator<<
(注意:这里 流插入<< 务必加上<> info._address;
		ifs >> info._port;
		ifs >> info._d;
	}

private:
	string _filename; // 配置文件
};

int main()
{
	ServerInfo winfo = { "https://legacy.cplusplus.com/reference/ios/ios/eof/"
                                                       , 80, {2022, 10, 11} };

	ConfigManager cf_txt("test.txt"); 
	cf_txt.WriteText(winfo);          把winfo中内容以文本形式写入"test.txt"文件


	ConfigManager cf_text("test.txt");
	ServerInfo rtinfo;
	cf_text.ReadText(rtinfo);         把"test.txt"文件中内容以文本形式读到rtinfo
	cout << rtinfo._address << "  " << rtinfo._port << "  " << rtinfo._d << endl;

	return 0;
}

 text.txt文件中写入了内容

C++:C++的IO流_第15张图片

注意!!!:流提取>> 读取时按空格或换行读取

WriteText流插入<< 务必加上<> 读取时按空格或换行读取

// 文本读写
	void WriteText(const ServerInfo& info)
	{
		//  1 2 4 8 16
		ofstream ofs(_filename);
		ofs << info._address << endl;    调用了string的operator<<重载
		ofs << info._port << endl;       底层会把int转成字符串再读取到ofs文件中
		ofs << info._d << endl;          调用了Date友元的operator<<
(注意:这里 流插入<< 务必加上<> info._address;
		ifs >> info._port;
		ifs >> info._d;
	}

————————————————————————————————————————————————————————————————————————————————————
    ConfigManager cf_text("test.txt");
    ServerInfo rtinfo;
    cf_text.ReadText(rtinfo);         把"test.txt"文件中内容以文本形式读到rtinfo
    cout << rtinfo._address << "  " << rtinfo._port << "  " << rtinfo._d << endl;

如果不加 WriteText 流插入<< 不加<

"https://legacy.cplusplus.com/reference/ios/ios/eof/"802022 10 11 ,日期类插入时带空格了,则 ReadText 读到ServerInfo rtinfo 中时,

rtinfo._address 读到内容是:"https://legacy.cplusplus.com/reference/ios/ios/eof/"802022
rtinfo._port 读到内容是: 10
rtinfo._d 读到内容是:_d._year=11,_d._month 和 _d._day 都没读到东西,则值是缺省值1

打印出来就是下面这种错误的情况:

C++:C++的IO流_第16张图片

WriteText流插入<< 加上<

C++:C++的IO流_第17张图片

三.stringstream

C++:C++的IO流_第18张图片

stringstream 是 istringstream 和 ostringstream 的功能集合版,一般不使用stringstream,就直接用 istringstream 和 ostringstream 即可

1.用途:将 整形/自定义类型 转字符串

C 语言中,如果想要将一个整形变量的数据转化为字符串格式,如何去做?
1. 使用 itoa() 函数
2. 使用 sprintf() 函数
但是两个函数在转化时,都得 需要先给出保存结果的空间 ,那空间要给多大呢,就不太好界定,
而且 转化格式不匹配时,可能还会得到错误的结果甚至程序崩溃
int main()
{
 int n = 123456789;
 char s1[32];
 _itoa(n, s1, 10);
 char s2[32];
 sprintf(s2, "%d", n);
 char s3[32];
 sprintf(s3, "%f", n);
 return 0;
}

2.功能使用

在C++中,可以使用stringstream类对象来避开此问题。
在程序中如果想要使用stringstream,必须要包含头文件。在该头文件下,标准库三个类:
istringstream、ostringstream 和 stringstream,分别用来进行流的输入、输出和输入输出操作,本文主要介绍stringstream。 stringstream主要可以用来:

(1)将数值类型数据格式化为字符串。

(整形转字符串类型没意义,to_string完全可以代替)

C++:C++的IO流_第19张图片

真正用法:自定义类型转字符串

class Date
{
	friend ostream& operator << (ostream& out, const Date& d);
	friend istream& operator >> (istream& in, Date& d);
public:
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}

	// 支持Date对象转换成bool
	operator bool()
	{
		// 这里是随意写的,假设输入_year为0,则结束
		if (_year < 1)
			return false;
		else
			return true;
	}
private:
	int _year;
	int _month;
	int _day;
};

istream& operator >> (istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}

ostream& operator << (ostream& out, const Date& d)
{
	out << d._year << " " << d._month << " " << d._day;
	return out;
}

oss<

C++:C++的IO流_第20张图片

字符串 转 自定义类型

C++:C++的IO流_第21张图片

你可能感兴趣的:(c++)