简介

流缓冲区是一种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。

#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中直接将字符输出。

#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){/*注意setp(buffer ,buffer + bufferSize - 1),所以pptr()==epptr()的时候,(也就是调用underflow的时候),pptr()指向缓冲区的最后一个位置(数组的最后一个位置)。所以pptr()指向有效内存。*/if(c != EOF){*pptr() = c;pbump(1);//使当前位置指向数组最后一个元素之后。}if(flushBuffer() == EOF){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;
}

STL之自定义缓冲区相关推荐

  1. Linux进程缓冲区大小,Linux IOCTL动态命令、动态|自定义缓冲区大小、IOCTL使用大缓冲区的问题...

    深夜睡不着,点根烟起来写点儿东西吧. 一个驱动程序除了具备读写设备的能力之外,其也应当具有对硬件控制的能力.在Windows下用户层代码使用API函数DeviceIoControl,通过传入驱动句柄, ...

  2. STL - Unorderedset - 自定义哈希函数

    1. hash工具类 hashval.hpp #ifndef _Core_HashVal_H_ #define _Core_HashVal_H_#include <functional>/ ...

  3. 【C++笔记】第二十二篇 STL

    C++的STL 1. STL 1.1 STL诞生 ① 长久以来,软件界一直希望建立一种可重复利用的东西. ② C++的面向对象和泛型编程思想,目的就是复用性的提升. ③ 大多数情况下,数据结构和算法都 ...

  4. 标准模板库(STL)学习指南之set集合

    /* 联合容器将值与关键字联合在一起,使用关键字来查找值, * 提供元素的快速访问,插入元素不能指定位置,容器自动处理插入位置 * STL 提供四种联合容器:set.multiset.map.mult ...

  5. day19(中)_IO流3(模拟缓冲区,装饰设计模式)

    1.MyBufferedReader和MyBufferedInputStream 1.模拟字符读取流的缓冲区: /*根据readLine原理:自定义一个类包含一个功能和readLine一致的方法来模拟 ...

  6. 拆包--缓冲区查找包头及包尾偏移

    缓冲区查找包头及包尾偏移 前言 一.采用动态数组QByteArray的自带函数 二.采用字节对比方法 测试代码 前言 根据前面所讲的内容封包拆包,当将网络中的数据读出存储在自定义缓冲区QByteArr ...

  7. C++ STL begin()和end()函数(深入了解,一文学会)

    C++ STL标准库提供的所有容器做了系统的讲解.无论是序列式容器还是关联式容器(包括哈希容器),不仅模板类内部提供有 begin() 和 end() 成员方法,C++ STL 标准库中还提供有同名且 ...

  8. 【Liunx】进程的程序替换——自定义编写极简版shell

    目录 进程程序替换[1~5] 1.程序替换的接口(加载器) 2.什么是程序替换? 3.进程替换的原理 4.引入多进程 5.系列程序替换接口的详细解析(重点!) 自定义编写一个极简版shell[6~8] ...

  9. 修改FILE缓冲区大小,改进写日志性能

    由于线上服务端程序,需要大量写入日志,将来入数据库库,以便做数据分析或者对账之用,可是发现日志打开后服务器变慢了,对外并发响应数量也减少了.于是分析了下日志写入函数fprintf.其写日志文件的顺序是 ...

最新文章

  1. 美观实用!Star 过万,用 Python 做交互式图形的这款工具火了!
  2. SAP LSMW 导入Open PO时价格不对问题之对策
  3. 计算机网络总结:第二章 应用层
  4. python图片分析中央气象台降水量预报_php采集自中央气象台范围覆盖全国的天气预报代码实例...
  5. 创建试图 失败_在失败中学习,MIT新研究显示,机器可以像婴儿一样学会理解人类目标...
  6. 09花冠钥匙计算机电路图,丰田花冠轿车发动机防盗系统设定
  7. UE4手册中文翻译速查表
  8. HDOJ 1394 Minimum Inversion Number
  9. 电子专业 英语词汇大全(持续更新)
  10. DAS、NAS、SAN、IPSAN、iSCSI-SAN及IDE、SAS、SCSI、iSCSI简介
  11. MySQL 系统自带的数据库有哪些?每个数据库的作用是什么?
  12. MOOC 苏小红C语言 第四周编程题
  13. 刷宝短视频Auto.js挂机源码讲解
  14. 网络攻防-20169213-刘晶-第五周作业
  15. 微信JSAPI支付 - 服务商模式下子商户 统一下单的注意事项
  16. 自由落体matlab代码,应用MATLAB辅助自由落体运动教学
  17. 【智能物流】河南烟草:新网络模式下的物流系统优化
  18. 网络7层协议详解——Network layer protocol
  19. JProfiler之java剖析工具
  20. cuda 10.0自带驱动不支持Geforce GTX 1060 Max-Q

热门文章

  1. 消费金融成新增长极,江苏银行零售转型如虎添翼
  2. STM32f103微妙延迟函数
  3. 《游戏学习》| 3d网页小游戏 | 公路赛车 源码
  4. synology nfs_如何为您的Synology NAS创建本地备份
  5. 名悦集团:汽车油耗突然飙升,或与这些驾驶习惯有关
  6. 科目二 总结(方向盘,离合器,刹车)
  7. 【数仓设计】宽表和窄表
  8. 王姨劝我学HarmonyOS鸿蒙2.0系列教程之一环境搭建跑起来模拟器!
  9. spring项目中使用slf4j和log4j2日志框架
  10. Android开发本地及网络Mp3音乐播放器(五)实现专辑封面图片