C++中的三种IO形式

流的概念

流就是流动,从某一处流向另一处的过程
在C++中,流的基本单位是字节,因此也称为字节流

流的四种状态

goodbit 有效状态
badbit 系统级别的错误,不可恢复
failbit 可恢复的错误
eofbit 到达了流的末尾

标准IO

标准IO四种状态和重置忽略函数的使用

io标准库,与IO常用函数

#include <iostream>

using std::cin;
using std::cout;
using std::endl;
using std::istream;

标准IO使用

#include <iostream>

using std::istream;
using std::cin;
using std::cout;
using std::endl;
using std::string;

void printStreamStatus(istream& is)//istream为自定义类型,表示输入函数
{
	//输入函数cin本质上是一个对象,内部也有相应的成员函数可以调用
	//good bad fail eof 与其上意义相同,为1为真,0为假
	cout << "is goodbit:" << is.good() << endl;
	cout << "is badbit:" << is.bad() << endl;
	cout << "is failbit" << is.fail() << endl;
	cout << "is eofbit" << is.eof() << endl;
}
void test0()
{
	int number = -1;
	
	printStreamStatus(cin);//去检查一下输入流当前的状态
	
	cin>>number;
	cout << "number:" << number << endl;
	
	printStreamStatus(cin);
	
	string line;
	cin >> line;
	cout << "line:" << line << endl;

	printStreamStatus(cin);
}
int main()
{
	test0();
	return 0;
}

以上代码,当输入正确格式(先输入int类型,再输入string类型),则输出结果

is goodbit:1
is badbit:0
is failbit0
is eofbit0
123
number:123
is goodbit:1
is badbit:0
is failbit0
is eofbit0
abc
line:abc
is goodbit:1
is badbit:0
is failbit0
is eofbit0

可以看到除goodbit以外其余皆为假,则流的状态是正常的
但当格式输入有误时,比如输入了string

is goodbit:1
is badbit:0
is failbit0
is eofbit0
abc
number:0
is goodbit:0
is badbit:0
is failbit1
is eofbit0
line:
is goodbit:0
is badbit:0
is failbit1
is eofbit0

number的值因为输入有误成了0(如果是输入了比int还大的数字,会打印越界后的数字而不是0),goodbit也成了假,输入stirng的时刻直接没有执行,goodbit也为假,但我们发现failbit为真,所以在第一次输入有误时我们可以弥补错误

void test0()
{
	int number = -1;

	printStreamStatus(cin);//去检查一下输入流当前的状态

	cin >> number;
	cout << "number:" << number << endl;
	printStreamStatus(cin);
	
	//重置流的状态
	cin.clear();
	//清空缓冲区
	cin.ignore(1024,'\n');//表示最多跳过1024个字节,直到遇到换行符
	

	string line;
	cin >> line;
	cout << "line:" << line << endl;

	printStreamStatus(cin);
}

此时我们发现无论第一次输入是否有误,都不会影响输入string的过程

假设我们在对cin重置后没有清空缓冲区,那么输入的数据会保留到下一次输入,也同样会取消string的输入,第一次输入的数据就是line的值

输出结果

is goodbit:1
is badbit:0
is failbit0
is eofbit0
abc
number:0
is goodbit:0
is badbit:0
is failbit1
is eofbit0
abc
line:abc
is goodbit:1
is badbit:0
is failbit0
is eofbit0

自定义安全输入

既然已经掌握了四种状态表示和如何重置流与清空缓冲区
那么可以试着写一个专门用于输入的函数

#include <iostream>

using std::istream;
using std::cin;
using std::cout;
using std::endl;
using std::string;

int readIntergerNumber()
{
	int number = -1;
	
	cout<<">:Please Input an interger number"<<endl;
	
	while(cin>>number && !cin.eof())//直到输入结束
	{
		if(cin.bad())
		{
			cout<<">:cin stream has broken"<<endl;
			return -1;
		}
		else if(cin.fail())
		{
			cout<<">:Please reInput a vaild interger number"<<endl;
			cin.clear();
			cin.ignore(1024,'\n');
		}
		else
		{
			cout<<">:Number:"<<number<<endl;
			return number;
		}
	}
}
void test1()
{	
	readIntergerNumber();
}
int main()
{
	test1();
	return 0;
}

缓冲区

注:当前代码在Linux系统中执行,其他编译器可能情况有所不同

三种缓冲区

全缓冲区:只有缓冲区满时才会输出/刷新
行缓冲区:只有缓冲区满/遇到换行时才会输出/刷新
非缓冲区:不带缓冲区,有多少数据就输出/刷新多少数据,类似于word编辑

#include <iostream>

using std::istream;
using std::cin;
using std::cout;	
using std::endl;
using std::string;

int main()
{
	cout<<"Hello<<endl;//可以认为endl就是换行符,也就表明cout使用的就是行缓冲区
	
	for(int i = 0;i < 512;++i)
	{
		cout<<'a';
	}
	Sleep(3000);//睡眠三秒
}

此时我们发现,当Hello打印后,过了三秒之后512个a才被打印出来
而当i循环改为1025时,可以发现打印完a之后才进行休眠
可知cout的默认缓冲区大小为1024字节

文件IO

三种输出函数

cout打印缓冲区内的数据
cerr打印错误信息
clog打印日志信息

#include <iostream>

using std::cin;
using std::cout;
using std::endl;
using std::cerr; 
using std::clog;

void test0()
{
	cout<<"cout"<<endl;
	cerr<<"cerr""<endl;
	clog<<"clog"<<endl;
}
int main()
{
	test0();
}

文件打印结果

cout

错误文件打印结果

cerr
clog

当将编译执行后的打印放进文件中,会发现文件中仅有cout输出
当指定编译执行后的打印以标准错误2放进文件中,会发现文件中有cerr,clog

ifstream

用于文件的读功能,属于文件IO内的一种自定义类型

#include <iostream>
#include <fstream>
#include <string>
#include <string.h>

using std::cin;
using std::cout;
using std::endl;
using std::cerr; 
using std::clog;
using std::string;
using std::ifstream;

void test1()
{
	ifstream ifs("namespace.cpp");//打开当前目录下的namespace.cpp文件
	
	if(!ifs.good())//文件不存在或其他问题
	{
		cout<<"ifstream open failed"<<endl;
		return;
	}

	string word;
	while(ifs>>word) //ifstream类型读入默认以空格和制表符分隔
	{
		cout<<word<<' ';
	}	
	
	//记得关闭文件
	ifs.close();
}
int main()
{
	test1();
}

注:namespace.cpp是我之前已经写过的一个cpp文件,你们可以选择一个txt类型的文件打开,也是可以的

输出结果

#include <iostream> //using namespace std以后可以禁掉了 using std::cin;// :: 作用域限定符 using std::cout; //using std::endl; extern int number2;//跨模块调用 //匿名空间内定义的变量无法跨模块调用,与static相同 namespace wd { int num = 1; void print() { cout << "print()" << std::endl; } namespace lr { int num; void display() { cout << "display" << std::endl; } }//end of namespace lr }//end of namespace wd namespace//匿名空间直接使用 { int num = 2; } namespace wd2 { void print(); }//命名空间内部函数可以像函数一样声明再定义,可以多次定义命名空间 //不同的是,一般函数声明可以多次,但定义只有一次 //命名空间就像容器,可以无限定义实体 //如果函数调用的形参与之前定义的变量重名,所调用的变量的值遵循就近原则 //如果有形参,值就是形参,如果没有,就找最近的之前相应变量的值 int main() { wd::print(); cout << wd::num << std :: endl; wd::lr::display(); cout << num << std::endl; using namespace wd; print(); cout << number2 << std::endl; wd2::print(); return 0; } namespace wd2 { int abc = 1; void print() { cout << abc << std::endl; } }

可以发现,这样输出的结果不是给人看的,需要一样东西来让他能够一行一行输出出来

在之前C++入门阶段我们接触到一个函数为getline,参数只能传字符数组而不能传string对象,但这也够用

#include <iostream>
#include <fstream>
#include <string>
#include <string.h>

using std::cin;
using std::cout;
using std::endl;
using std::cerr;
using std::clog;
using std::string;
using std::ifstream;

void test1()
{
	string filename("namespace.cpp");
	ifstream ifs(filename);//用字符串也可以简便ifstream的传参过程

	if(!ifs.good())
	{
		cout<<"ifstream open file failed"<<endl;
		return;
	}
	
	char buff[1024] = {0};//创建buff数组存储一行数据
	while(ifs.getline(buff,1000))//ifstream类中有getline成员函数,可直接调用
	{
		cout<<buff<<endl;
		memset(buff,0,sizeof buff);
	}
	
	ifs.close();
}
int main()
{
	test1();
}

输出结果

#include <iostream>

//using namespace std以后可以禁掉了
using std::cin;// :: 作用域限定符
using std::cout;
//using std::endl;

extern int number2;//跨模块调用
//匿名空间内定义的变量无法跨模块调用,与static相同

namespace wd
{
int num = 1;

void print()
{
        cout << "print()" << std::endl;
}
        namespace lr
        {
        int num;
        void display()
        {
                cout << "display" << std::endl;
        }

        }//end of namespace lr
}//end of namespace wd
namespace//匿名空间直接使用
{
int num = 2;
}
namespace wd2
{
        void print();
}//命名空间内部函数可以像函数一样声明再定义,可以多次定义命名空间
//不同的是,一般函数声明可以多次,但定义只有一次
//命名空间就像容器,可以无限定义实体

//如果函数调用的形参与之前定义的变量重名,所调用的变量的值遵循就近原则
//如果有形参,值就是形参,如果没有,就找最近的之前相应变量的值
int main()
{
        wd::print();
        cout << wd::num << std :: endl;
        wd::lr::display();
        cout << num << std::endl;
        using namespace wd;

        print();

        cout << number2 << std::endl;
        wd2::print();

        return 0;
}
namespace wd2
{
int abc = 1;
void print()
{
        cout << abc << std::endl;
}
}

此时打印的代码就非常可观了

ostream

ostream对象用于文件写入

成员函数

ofs,open(string);打开当前目录下的string文件
ofs.write(string,len);//第一个参数为要写入的字符串,第二个参数指定写入到多少长度为止
ofs.tellp();//返回当前流游标位置
ofs.seekp(n);流回到指定位置,0表示起始位置

#include <iostream>
#include <fstream>
#include <string>
#include <string.h>

using std::cin;
using std::cout;
using std::endl;
using std::cerr;
using std::clog;
using std::ifstream;
using std::ofstream;
using std::fstream;
using std::string;

void otest()
{
	ofstream ofs;
	ofs.open("test.txt", std::ios::out | std::ios::app);
	//out为open函数默认参数,表示不要求文件存在,
	//如果文件存在则进行重定向
	//如果文件不存在则创建文件并写入
	//app即append追加模式

	if (!ofs)//简便操作,可以不用调用good
	{
		cout << "ofstream file open failed" << endl;
		return;
	}

	//对文件开始写入
	ofs << "this is a test" << endl;

	size_t pos = ofs.tellp();

	ofs.write("this is a new test\n", strlen("this is a new test\n")) << endl;

	//记得关闭文件
}
int main()
{
	otest();
}

fstream

fstream能进行读写操作,存在于fstream模板中
既包含ifstream的成员函数,也包含ofstream的成员函数

#include <iostream>
#include <fstream>

using std::cout;
using std::cin;
using std::endl;
using std::string;
using std::fstream;

void ftest()
{
	//fstream默认规定打开的文件必须存在,且要从文件的开头读写
	fstream fs("test.txt", std::ios::in | std::ios::out | std::ios::app);

	if (!fs)
	{
		cout << "fstream file open failed " << endl;
		return;
	}

	int number = -1;

	for (int i = 0; i < 4; ++i)
	{
		cin >> number;
		fs << number << ' ';
	}
	cout << endl;

	//当使用tell查找游标位置时,tellg是输入流,tellp是输出流

	fs.seekp(0);

	char buff[1024] = { 0 };

		while (fs.getline(buff, sizeof buff))
		{
			cout << buff;
			memset(buff, 0, sizeof buff);
		}

	fs.close();
}
int main()
{
	ftest();
	return 0;
}

字符串IO

模板库

自定义类型
istringstream将字符串转换为其他类型
ostringstream将缓冲区内数据转化为字符串
stringstream

istringstream

#include <iostream>
#incldue <sstream>

using std::cin;
using std:;cout;
using std::endl;

void test0()
{
	istringstream iss("1 2 3 4 5 6");
	
	string word;
	
	while(iss>>word)
	{
		cout<<word<<endl;
		//当读入到的是缓冲区中,可以以其他类型读入
	}
}
int main()
{
	test0();
}

ostringstream

#include <iostream>
#include <sstream>
using std::cout;
using std::endl;
using std::string;
using std::istringstream;
using std::ostringstream;
using std::stringstream;

void test1()
{
	int number = -1;
	int id = 101;
	
	ostringstream oss;
	
	oss << "number:"<<number<<' '<<"id:"<<id<<endl;
	
	string str = oss.str();//获取oss流中字符串数据
	
	cout<<str<<endl;
}
int main()
{
	test1();
}

输出结果

number:-1 id:101
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

涅槃豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值