C++的IO流简介

C++的IO流简介,第1张

- 本人的LeetCode账号:魔术师的徒弟,欢迎关注获取每日一题题解,快来一起刷题呀~

  • 本人Gitee账号:路由器,欢迎关注获取博客内容源码。



    文章目录


    • 一、C语言的输入输出


    • 二、C++的输入输出流

      • 1 流是什么
      • 2 C++的标准IO流
      • 3 C++的文件IO流
      • 3 C++的字符串IO流

一、C语言的输入输出

  C语言主要使用scanfprintf与输入输出设备交互,大概是这样的:


二、C++的输入输出流 1 流是什么

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


   C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存) 输入和从内存向外部输出设备(显示器)输出的过程。


这种输入输出的过程被形象的比喻为“流”。


  它的特性是:有序连续、具有方向性

  为了实现这种流动,C++定义了I/O标准类库,这些每个类都称为流/流类,用以完成某方面的功能。


2 C++的标准IO流

  C++的这些cin cout等都是一些全局对象,关系如下,ios是其基类,它们之间有继承的关系。


  之前我们说过,coutcin能自动识别类型的原因是因为它们做了运算符重载,同时这些运算符有构成了函数重载。


  所以自定义类型需要我们自己做函数重载才可以用。


cin cout效率提升

  ios::sync_with_stdio(false);这条语句可以把cinscanfcoutprintf的同步关掉,可以提升cin的速度,不过这时cinscanf混用就会出错。


  没有这条语句时,cin cout为了保证混用printfscanf时文件指针不混乱做了很多工作,所以速度要慢,关掉速度就会快很多。


读取一行

  C语言读取一行,可以用fgets,C++可以用getline


  cin cout相比scanfprintf的优势就在于自定义类型对象在重载后可以直接使用<<>>输入输出,不比每次都要自己用scanfprintf组合。


多组测试用例

  C语言写法:

while (scanf("", ) != EOF)

  因为scanf会返回读取的个数,当读取的个数是0的时候,就结束了。


  C++写法:

while (cin >> )

  这里判断的表达式是判断的cin这个istream对象,按理说不应该啊,我们之前值接触过整形和布尔值做逻辑判断,这里怎么对象也能做逻辑判断了,是因为类型运算符重载,当用istream对象进行逻辑判断时,它就会调用这个类型运算符重载,使其返回一个布尔值。


  我们的一个简单测试:

class B
{
public:
	B(int b = 0) : _b(b)
	{}
	operator bool()
	{
		return _b != 0;
	}
private:
	int _b;
};

int main()
{
	B b1(11);
	if (b1)
	{
		cout << "隐式类型转换一样的operator bool()" << endl;
	}
	return 0;
}

  所以上面的原理就是在istream类内部有一个标志符,当读取结束的时候,就会给这个标志符该为false,然后operator bool()返回这个标志符作为真假性即可。


  进一步测试:

class B
{
public:
	B(int b = 0) : _b(b)
	{}
	operator bool()
	{
		return _b != 0;
	}
	friend istream& operator>>(istream& in, B& b);
	friend ostream& operator<<(ostream& out, B& b);
private:
	int _b;
};
istream& operator>>(istream& in, B& b)
{
	in >> b._b;
	return in;
}

ostream& operator<<(ostream& out, B& b)
{
	out << b._b;
	return out;
}

int main()
{
	B b1(11);
	while (b1)
	{
		cin >> b1;
		cout << b1 << endl;
	}
	return 0;
}
3 C++的文件IO流

  假如我们要把如下结构的对象写入文件中:

struct ServerInfo
{
 char _ip[32]; // ip
 int _port; // 端口
};

  使用C语言的话,首先我们需要用fopenfclose打开和关闭文件,文件的读写有两种方式,二进制读写可以使用fwritefread作为接口,直接写出内存中你的数据是怎么二进制存储的。


还有一种写字符串来读写文件,接口为fputsfgets打印接收一行,fprintffscanf来格式化字符串读写。


写:

void testC_bin()
{
	ServerInfo info = { "127.0.0.1", 80 };
	FILE* pf = fopen("test.bin", "wb");
	assert(pf);
	fwrite(&info, sizeof(info), 1, pf);
	fclose(pf);
}

读:

void testC_R_bin()
{
	ServerInfo info;
	FILE* pf = fopen("test.bin", "rb");
	assert(pf);
	fread(&info, sizeof(info), 1, pf);
	cout << info._ip << ' ' << info._port << endl;
	fclose(pf);
}

  二进制读写比较简单,但缺陷是写出去的东西文件中看不见。


  字符型读写测试:

void testC_W_S()
{
	ServerInfo info = { "127.0.0.1", 80 };
	FILE* pf = fopen("test.txt", "w");
	assert(pf);
	fprintf(pf, "%s %d", info._ip, info._port);
	fclose(pf);
}
void testC_R_S()
{
	ServerInfo info;
	FILE* pf = fopen("test.txt", "r");
	assert(pf);
	fscanf(pf, "%s %d", info._ip, &info._port);
	printf("%s %d\n", info._ip, info._port);
	fclose(pf);
}

  注意fscanfscanf类似,对多个数据,它们都以' '\n区分。


  我们用C++的风格玩一下,包头文件


  C++中,ofstream是写文件流的类:

  构造函数中的模式类型:

  这里是用比特位表示状态,和Linux中的系统调用状态类似,可以|来把状态弄到一起。


  它的写的成员函数:

  框架:

// 管理文件名
class ConfigManager
{
public:
	ConfigManager(const string& str): _filename(str)
	{}
	void writeBin(const ServerInfo& info)
	{
		ofstream of(_filename.c_str(), ios_base::binary | ios_base::out);
		of.write((const char*)(&info), sizeof(info));
	}

	void readBin(ServerInfo& info)
	{
		ifstream of(_filename.c_str(), ios_base::binary | ios_base::in);
		of.read((char*)(&info), sizeof(info));
	}

	void writetxt(const ServerInfo& info)
	{
		// 默认参数就是文件读写
		ofstream of(_filename.c_str());
		of << info._ip << ' ' << info._port;
	}

	void writetxt(ServerInfo& info)
	{
		// 默认参数就是文件读写
		ifstream ifs(_filename.c_str());
		ifs >> info._ip >> info._port;
	}
private:
	string _filename;
};

  二进制写:

void testCPPWbin()
{
	ServerInfo info = { "192.0.0.1", 80 };
	ConfigManager con("myconfig.bin");
	con.writeBin(info);
}

  二进制读:

void testCPPRbin()
{
	ServerInfo info;
	ConfigManager con("myconfig.bin");
	con.readBin(info);
	cout << info._ip << ' ' << info._port << endl;
}

文本写:

void testCPPWtxt()
{
	ServerInfo info = { "191.0.0.1", 80 };
	ConfigManager con("myconfig.txt");
	con.writetxt(info);
}

文本读:

void testCPPRtxt()
{
	ServerInfo info;
	ConfigManager con("myconfig.txt");
	con.readtxt(info);
	cout << info._ip << ' ' << info._port << endl;
}

  二进制读写和C类似,不过文本读写可以支持operator >>operator <<,可以对自定义类型重载这些运算符,然后就可以像coutcin那样进行文本读写。


  对自定义类型,这里需要去掉const,不知道为啥。


class Date
{
public:
	Date(int year = 2000, int month = 1, int day = 1)
		: _year(year), _month(month), _day(day)
	{}
	friend ofstream& operator<<(ofstream& out, Date& d);
private:
	int _year;
	int _month;
	int _day;
};

ofstream& operator<<(ofstream& out, Date& d)
{
	out << d._year << ' ' << d._month << ' ' << d._day << endl;
	return out;
}

void writetxt(ServerInfo& info)
{
    // 默认参数就是文件读写
	ofstream of(_filename.c_str());
    of << info._ip << ' ' << info._port << ' ';
	of << info._d;
}
3 C++的字符串IO流

  头文件


ostringstream:把一个自定义结构中的内容读成一个字符串,类似sprintf


  它支持operator<<,可以从结构中把内容直接转字符串,注意分割,如果要获得转成的字符串,用.str()即可:

istringstream:把一个字符串中的内容一部分一部分读取出来,类似sscanf


  它也支持operator>>,可以从字符串中把内容读出来,注意需要分隔符。


  在网络编程中,可以用这两个东西来完成序列化和反序列化的任务。


  一个测试:

class Date
{
public:
	Date(int year = 2000, int month = 1, int day = 1)
		: _year(year), _month(month), _day(day)
	{}
	friend ofstream& operator<<(ofstream& out, Date& d);
	friend ostringstream& operator<<(ostringstream& out, Date& d);
	friend ostream& operator<<(ostream& out, Date& d);
	friend istringstream& operator>>(istringstream& sin, Date& d);
private:
	int _year;
	int _month;
	int _day;
};

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

ofstream& operator<<(ofstream& out, Date& d)
{
	out << d._year << ' ' << d._month << ' ' << d._day << endl;
	return out;
}

ostringstream& operator<<(ostringstream& out, Date& d)
{
	out << d._year << ' ' << d._month << ' ' << d._day << endl;
	return out;
}

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

struct Personinfo
{
	string _name;
	int _age;
	Date _d;
};

int main()
{
	Personinfo p = { "路由器", 20 };
	ostringstream oss;
	oss << p._name << " " << p._age << " ";
	oss << p._d;// 这里要换行 不知道为什么
	cout << oss.str() << endl;
	string tmp = oss.str();
	istringstream iss(tmp);
	Personinfo p1;
	iss >> p1._name >> p1._age;
	iss >> p1._d;
	cout << p1._name << '*' << p1._age << '+' << p1._d << endl;
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/563211.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-02
下一篇 2022-04-02

发表评论

登录后才能评论

评论列表(0条)

保存