iostream : 可用于输入和输出操作 所有这些类以及文件流类都派生自以下类:ios 和 streambuf。因此,文件流和 IO 流对象的行为相似。 所有流对象也有一个关联的数据成员流缓冲类。 简单地说,streambuf 对象是流的缓冲区。当我们从流中读取数据时,我们不会直接从源读取它,而是从链接到源的缓冲区中读取它。 1)stream_object.rdbuf():返回指向stream_object的流缓冲区的指针 2)stream_object.rdbuf(streambuf * p):设置流缓冲区为p指向的对象 namespace std; int main() { fstream file; file.open("cout.txt", ios::out); string line; streambuf * stream_buffer_cout = cout.rdbuf(); streambuf* stream_buffer_cin = cin.rdbuf(); streambuf*
iostream : 可用于输入和输出操作 所有这些类以及文件流类都派生自以下类:ios 和 streambuf。因此,文件流和 IO 流对象的行为相似。 所有流对象也有一个关联的数据成员流缓冲类。 简单地说,streambuf 对象是流的缓冲区。当我们从流中读取数据时,我们不会直接从源读取它,而是从链接到源的缓冲区中读取它。 1)stream_object.rdbuf():返回指向stream_object的流缓冲区的指针 2)stream_object.rdbuf(streambuf * p):设置流缓冲区为p指向的对象 { fstream file; file.open("cout.txt", ios::out); string line; // cout 的备份流缓冲区 streambuf streambuf* stream_buffer_file = file.rdbuf(); // 将 cout 重定向到文件 cout.rdbuf(stream_buffer_file
里面声明了一些带参数的操纵算子 sstream,sstream里面声明了basic_stringbuf模板类、basic_istringstream模板类、basic_ostringstream模板类 streambuf ,streambuf里面声明了basic_streambuf模板类 上面说到iosfwd对输入输出的类模板做了实例化,我们截取一段代码,如下: /// Base class for @c char typedef basic_streambuf<char> streambuf; /// Base class for @c char input streams.
:unlock() Undefined symbol: std::__1::recursive_mutex::try_lock() Undefined symbol: std::__1::basic_streambuf <char, std::__1::char_traits<char> >::~basic_streambuf() Undefined symbol: std::__1::recursive_mutex: basic_iostream<char, std::__1::char_traits<char> >::~basic_iostream() Undefined symbol: std::__1::basic_streambuf <char, std::__1::char_traits<char> >::basic_streambuf() Undefined symbol: std::__1::recursive_mutex:: basic_ostream<char, std::__1::char_traits<char> >::~basic_ostream() Undefined symbol: std::__1::basic_streambuf
1.istream的构造函数 从istream头文件中截取一部分关于构造函数的声明和定义,如下: public: explicit basic_istream(__streambuf_type this; } 可以看到istream类的默认构造函数是保护类型,而带参数的构造函数则是公有的,根据public和protected的功能,我们要定义一个istream对象,必须要在参数中传入streambuf main() { filebuf buf; istream iii(&buf); return 0; } 这里应该有人会疑惑,怎么构造函数传的是filebuf类型的入参呢,原因是streambuf 的构造函数也是保护类型,且只有一个无参构造函数,所以streambuf是不能直接定义一个对象的,需要使用它的继承者stringbuf或者filebuf,这里使用了filebuf。 //同理,是以上函数终止字符为换行符 __istream_type& get(__streambuf_type& __sb) { return this->get(_
_err) this->setstate(__err); } return *this; } 以输出一个字符为例,put函数是调用了缓冲区基类basic_streambuf 小贴士:很显然,对于上面第二点,调用overflow函数,是使用了c++中多态,对于streambuf::overflow,它是一个虚函数,真正的实现是在stringbuf和filebuf里面。 1.2.3 iostream的底层实现 对于istream,ostream,iostream而言,他们的缓冲区使用的是streambuf,但streambuf的构造函数是保护类型的,所以它是没有办法直接生成一个对象的 ,也是可以理解的,因为streambuf既没有提供缓冲区,也没有提供一个外部设备,所以它本来也是不能直接使用的,它只是作为一个基类供stringbuf和filebuf调用。 类型的对象,所以可以猜测到stdio_sync_filebuf应该是继承于streambuf的,找到stdio_sync_filebuf.h头文件,看到stdio_sync_filebuf果然是继承于basic_streambuf
'\n' istream& get (char* s, streamsize n, char delim) //指定读取停止字符 delim stream buffer (3): //内容读取到 streambuf istream& get (streambuf& sb);//默认delim是换行字符'\n' istream& get (streambuf& sb, char delim);//指定读取停止字符 delim 下面的程序演示get()读取到streambuf 的用法。 #include <iostream> // std::cout, std::streambuf, std::streamsize #include <fstream> // std: std; int main () { std::ifstream ifs ("test.txt"); std::ofstream ofs ("out.txt"); std::streambuf
收发流管理在网络库中处于一个非常重要的位置,与其他rpc框架不同,phxrpc在这方面可谓独辟蹊径,将socket与iostream和streambuf结合起来,完成了缓冲区的设计。 CreateSocket(accepted_fd)}; UThreadTcpStream stream; stream.Attach(socket);//关键点在这里,Attach里将streambuf iostream进行绑定 stream.Attach里调用了NewRdbuf方法 void BaseTcpStream::NewRdbuf(BaseTcpStreamBuf * buf) { std::streambuf * old = rdbuf(buf); delete old; } BaseTcpStream继承了std::iosream,BaseTcpStreamBuf继承了std::streambuf ,上面的rdbuf方法将对iostream的操作转到了streambuf上 进入正题,来一起看下phxrpc怎样处理输入流。
从流中获取数据的操作称为“提取”(输入)操作 向流中添加数据的操作称为“插入”(输出)操作 标准输入输出流 文件流 字符串流 二、流类库继承体系、四个输入输出对象 流库具有两个平行的基类:streambuf 和 ios 类,所有流类均以两者之一作为基类 streambuf 类提供对缓冲区的低级操作:设置缓冲区、对缓冲区指针操作区存/取字符 ios_base、ios 类记录流状态,支持对streambuf 扩展 streambuf 在缓冲区提取和插入的管理 filebuf:使用文件保存字符序列。包括打开文件;读/写、查找字符 如下图: ?
1.2 输入输出中比较重要的类streambuf:提供缓冲区,有成员方法 填满缓冲区、获取缓冲区内容、刷新缓冲区、管理缓冲区ios_base:表示流的一般属性 比如文件是否打开、是二进制流还是文本流等等 ios:基于ios_base,并且它包含了一个指针成员指向一个streambuf对象ostream:继承自ios类并提供了输出方法istream:继承自ios类并提供了输入方法iostream:继承自ostream 个用于宽字符流)cin对象:对应标准输入流,默认情况下这个流与标准输入设备匹配(键盘);wcin对象用于wchar_t类型;cout对象:对应标准输出流,默认情况下这个流与标准输出设备匹配(显示器),借助streambuf
4.istream &get(streambuf &,char)是指从流中取的字符存入streambuf 对象,直到终止符或文件末尾.。
4.IO流类库的组成结构 IO流类库在不同平台的具体实现上,可能会有所变化,但从总体设计上来看,C++流库主要由两个流类层次组成: (1)以streambuf类为父类的类层次 主要完成信息通过缓冲区的交换 streambuf类为所有的streambuf类层次对象设置了一个固定的内存缓冲区,动态划分为两部分: 用做输入的取区,用取指针指示当前取字符位置。 (2)以ios类为父类的类层次 ios类及其派生类是在streambuf类实现的通过缓冲区的信息交换的基础上,进一步增加了各种格式化的输入/输出控制方法。 它们为用户提供使用流类的接口,它们均有一个指向streambuf的指针。
failbit 往流缓冲区写入或者读取数据发生错误时,会被置为failbit goodbit 上面三种都没有时,就是goodbit 另外ios_base另外定义了一个保护成员iostate _M_streambuf_state 函数原型如下: //返回当前流状态 iostate rdstate() const { return _M_streambuf_state; } //默认清除所有异常状态,置为goodbit
为了方便一些同学想单独调试日志部分代码,笔者把那些“额外代码”去掉了,做了一个可以单独运行的模块,你可以在这里获取代码:Tars-log demo) 日志部分的类继承关系要复杂一些,且涉及到std::basic_streambuf #include <iostream> #include <string> using namespace std; class LoggerBuffer : public std::basic_streambuf LoggerBuffer变量和ostream之间关系有些帮助 [13.3stream.jpg] 13.3 小结 线程池部分逻辑很清晰,接收任务,循环等待,常规套路 LoggerBuffer继承了std::basic_streambuf
string的缓冲区,默认可读可写 explicit basic_stringbuf(ios_base::openmode __mode = ios_base::in | ios_base::out) : __streambuf_type basic_stringbuf(const __string_type& __str, ios_base::openmode __mode = ios_base::in | ios_base::out) : __streambuf_type string's len is " << istr.rdbuf()->in_avail() << endl; return 0; } 这里也顺便展示了一下str函数的用法,in_avail是streambuf
pair< boost::shared_ptr<boost::asio::ip::tcp::socket>, boost::shared_ptr<boost::asio::streambuf boost::shared_ptr<boost::asio::ip::tcp::socket> ptrCurSock, boost::shared_ptr<boost::asio::streambuf >( new boost::asio::streambuf() ) ); // Step 5.2 设置Socket接收数据回调 boost ::shared_ptr<boost::asio::streambuf> ptrSockStreamBuff = g_stServerSockMap[ptrCurSock->native_handle( 另外,streambuf流用于管理发送或接收缓冲,但是在发送或接收完后,要执行consume函数移出或commit移入缓冲区,否则数据不会被销毁。
rdbuf() 函数的语法格式有 2 种,分别为: streambuf * rdbuf() const; streambuf * rdbuf(streambuf * sb); streambuf 是 in.txt 文件,等待读取 ifstream fin("test.txt"); //打开 out.txt 文件,等待写入 ofstream fout("out.txt"); streambuf *oldcin; streambuf *oldcout; char a[100]; //用 rdbuf() 重新定向,返回旧输入流缓冲区指针 oldcin = cin.rdbuf /output.txt"); //输出文件 streambuf *cinbackup; streambuf *coutbackup; coutbackup= cout.rdbuf(fout.rdbuf( ; while (cin>>line){ //从input.txt文件读入 cout<<line<<endl; //写入 output.txt }; // restore standard streambuf
pair< boost::shared_ptr<boost::asio::ip::tcp::socket>, boost::shared_ptr<boost::asio::streambuf boost::shared_ptr<boost::asio::ip::tcp::socket> ptrCurSock, boost::shared_ptr<boost::asio::streambuf >( new boost::asio::streambuf() ) ); // Step 5.2 设置Socket接收数据回调 boost ::shared_ptr<boost::asio::streambuf> ptrSockStreamBuff = g_stServerSockMap[ptrCurSock->native_handle( 另外,streambuf流用于管理发送或接收缓冲,但是在发送或接收完后,要执行consume函数移出或commit移入缓冲区,否则数据不会被销毁。 UDP和TCP的类似,我就不再多写一个demo了。
从ostream头文件中截取一部分关于构造函数的声明和定义,如下: public: //explicit用来防止由构造函数定义的隐式转换 explicit basic_ostream(__streambuf_type this; } 可以看到ostream类的默认构造函数是保护类型,而带参数的构造函数则是公有的,根据public和protected的功能,我们要定义一个ostream对象,必须要在参数中传入streambuf open failed" << endl; return -1; } ostream out(&buf); return 0; } 与istream一样,因为streambuf
ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf ostream> #include<queue> #include<set> #include<sstream> #include<stack> #include<stdexcept> #include<streambuf