http://m.blog.csdn.net/article/details?id=10992117
http://www.cnblogs.com/my_life/articles/4792188.html

int underflow();
Virtual function called by other member functions to get the current character in the controlled input sequence without changing the current position.
(当无数据可读时被其他函数调用,默认行为是返回读指针下的内容(如果有)或者EOF(如果没有剩余数据),而不移动读指针)
It is called by public member functions such as sgetc to request a new character when there are no read positions available at the get pointer (gptr).
Its default behavior in streambuf is to return the character pointed by gptr (without advancing it), if characters are available at that position. Or, if there are no characters, the function always returns EOF (indicating failure), but derived classes can override this behavior to modify the gptr and egptr internal pointers in such a way that more characters from the input sequence may be made accessible through the buffer (if these are available). Both filebuf and stringbufoverride this virtual member function.
========
int overflow (int c = EOF);
(当无剩余空间可写时,被其他函数调用,而不移动写指针,默认行为是返回EOF)
Virtual function called by other member functions to put a character into the controlled output sequence without changing the current position.
It is called by public member functions such as sputc to write a character when there are no writing positions available at the put pointer (pptr).
Its default behavior in streambuf is to always return EOF (indicating failure), but derived classes can override this behavior to attempt to write the character directly and/or to alter pptr and other internal pointers so that more storage is provided, potentially writing unwritten characters to the controlled output sequence. Both filebuf and stringbuf override this virtual member function.
====================
简介
流缓冲区是一种I/O缓冲区,接口由basic_streambuf定义。针对字符型别char和wchar,标准程序库分别提供预先定义好的流缓冲区(streambuf)和宽字符流缓冲区(wstreambuf)。尤其是在特殊通道上,各类可以当做基类。
- 函数eback(),gptr()和egptr()构成了read(input)缓冲区的界面。
- 函数pbase(),pptr(),epptr()构成了write(output)缓冲区的界面。
pbase()是指output stream缓冲区的起始位置。 pptr()是当前写入位置。 epptr()是output 缓冲区的结尾。 pbase()至pptr()之间的序列字符已被写至相应的输出通道,但未被清空。
输出缓冲区
对于程序员和程序开发者来说,类basic_streambuf仅仅是发送(sent)和提取(extracted)字符的地方。通常有两个公共函数,用于写入字符。
int streambuf::sputc( int nCh );
int streambuf::sputn( const char* pch, int nCount );
函数sputc发生错误时,会返回traits_type::eof()。
成员函数sputc()可用来向缓冲区中写入一个字符,如果当时有一个空的改写位置,字符就会被复制到该位置上。之后,指向当前改写位置的那个指针就会加1。如果缓冲区是空的(不够写了),就调用虚函数overflow()将output缓冲区的内容发送至对应的输出管道中(即写入到真实的设备上)。
所以,通过重载overflow()函数可以自定义streambuffer。
缓冲区无剩余空间可写时,overflow()会被调用。
#include <IOSTREAM>
#include <streambuf>
#include <LOCALE>
#include <CSTDIO>
using namespace std;
class outbuf : public std::streambuf
{
protected:
virtual int_type overflow(int_type c)
{
if(c != EOF)
{
c = std::toupper(c ,getloc());
if(putchar(c) == EOF)
{
return EOF;
}
}
return c;
}
};
void main()
{
outbuf ob;
std::ostream out(&ob);
int num = 56;
out << "56 十六进制数值: " << std::hex << std::showbase << num << endl;
}
上面是一个没有缓冲区的demo。因为缓冲区为空,每输出一个字符都会调用一次overflow()函数,在overflow中直接将字符输出。
The thing to remember is that the basic_[io]stream classes handle formatting, nothing else. In particular, they break up on whitespace.
The actual reading, writing, and storing of data is handled by the basic_streambuf family.
#include <iostream> #include <io.h> #include <streambuf> #include <cstdio> using namespace std; static const int bufferSize = 10; class outbuf : public std::streambuf //这是缓冲 { protected: char buffer[bufferSize];//定义一个数组表示缓冲区。 public: outbuf(){ setp(buffer ,buffer + bufferSize - 1);//设置streambuf对象的缓冲区; } virtual ~outbuf(){ sync();//程序退出时,将数组中的残余数据输出至外部设备。 } protected: int flushBuffer() { int num = pptr() - pbase(); if(write(1 ,buffer , num) != num)//输出。 { return EOF; } pbump(-num);//将当前写指针清空,指向缓冲区的开始位置。 return num; } virtual int_type overflow(int_type c) //参数c代表待插入的字符 { /* 注意setp(buffer ,buffer + bufferSize - 1), 所以pptr()==epptr()的时候,(也就是调用underflow的时候), pptr()指向缓冲区的最后一个位置(数组的最后一个位置)。所以pptr()指向有效内存。 */ if(c != EOF){ *pptr() = c; pbump(1);//使当前位置指向数组最后一个元素之后。 //pptr指针后移 } if(flushBuffer() == EOF) //已经发生了overflow,说明,pptr已经移动到了epptr,此时需要将写缓冲区中的数据(pbase到pptr之间的数据)写入到真实设备 { return EOF; } return c; } virtual int sync() { if(flushBuffer() == EOF) { return -1; } return 0; } }; class fdostream : public std::ostream //这是格式化 { protected: outbuf buf; public: fdostream(int fd):ostream(0) { rdbuf(&buf);//设置streambuf对象。 } }; void main() { fdostream out(1); out << "51 hexadecimal: " << std::hex << std::showbase << 51 << endl; }
输入缓冲区
函数sgetc()和sbumpc()可以从streambuf中读取一个字符,不同之处是sbumpc()会使当前指针后移,而sgetc()仅返回当前字符。
如果缓冲区为空,就没有可用字符了。缓冲区必须重新补给。如果没有可用字符,函数sbumpc()会调用虚函数uflow(),而uflow()的默认行为是调用underflow(),移动“读取指针”。
需要说明一下的时,eback()返回缓冲区中有效数据的起始位置。epptr()返回缓冲区有效数据末端位置。pptr()返回当前读取位置。这里需要注意的是,eback()并不一定等于pptr(),因为为了支持回退,eback()和pptr()之间存储已经读取过的字符。而epptr()并不一定是缓冲区数组的最后一个元素,因为可能没有从输入设备读取这么多的数据。
在给出demo之前,由于输入缓冲区支持回退,也就是读取指针可以左移,读取之前读取过的字符。所以,在重写函数underflow自定义自己的streambuf时,也需要支持这种特性。
#include <iostream>
#include <streambuf>
#include <cstring>
#include <io.h>
using namespace std;
static const int bufferSize = 10;
static const int maxBackNum = 4;
class inbuf : public std::streambuf
{
protected:
char buffer[bufferSize];
public:
inbuf()
{
setg(buffer + maxBackNum ,buffer + maxBackNum ,buffer + maxBackNum);
}
protected:
virtual int_type underflow()
{
if(gptr() < egptr())
{
return *gptr();
}
int numputback;
numputback = gptr() - eback();
if(numputback > maxBackNum)
numputback = maxBackNum;
memcpy(buffer + maxBackNum - numputback ,gptr() - numputback ,numputback);
int num ;
num = read(0 ,buffer + maxBackNum ,bufferSize - maxBackNum);
if(num < 0)
return EOF;
setg(buffer + (maxBackNum - numputback) ,buffer + maxBackNum ,buffer + maxBackNum + num);
return *gptr();
}
};
void main()
{
inbuf ib;
std::istream in(&ib);
char c;
for(int i = 1 ;i <= 20 ;i++)
{
in.get(c);
cout << c << flush;
if(i == 8)
{
in.unget();
in.unget();
}
}
cout << endl;
}
浙公网安备 33010602011771号