C/C++编程:流缓冲类std::basic_streambuf 

1060 篇文章 307 订阅
template<
    class CharT,
    class Traits = std::char_traits<CharT>
> class basic_streambuf;

 

\

该模板类的主要作用是抽象原生设备

该模板被设计为所有流缓冲区类的基础虚拟类:

  • IO流对象象 std::basic_istream 及 std::basic_ostream ,还有所有派生自它们的对象( std::ofstream 、std::stringstream 等),都完全以 std::basic_streambuf 实现。
  • 在内部, basic_streambufclass是精心设计的基类,旨在为所有派生类提供统一的公共接口:这些公共函数调用派生类可以重写以实现特定行为的虚拟受保护成员。这些被覆盖的虚拟功能可以通过一组受保护的函数访问内部的basic_streambuf 类

流缓冲区对象在内部至少保留:

  • 一种 locale 对象,用于与语言环境相关的操作。
  • 一组内部指针,用于保留输入缓冲区:  ebackgptregptr
  • 一组内部指针,用于保留输出缓冲区: pbasepptrepptr

 

 

模板实例化

成员函数

                                               本地环境

pubimbue

调用 imbue()

getloc

获得相关本地环境的副本

pubimbue

locale pubimbue (const locale& loc);

功能:

  • 将loc 关联到stream buffer.

返回值:

  • 返回stream buffer.在调用这个函数之前的locale

 getloc

locale getloc() const;

功能:

  • 获取当前语言环境
  • 如果成员函数 pubimbue 已经被这个 stream buffer调用,那么返回设置的值,否则返回当前的全局语言环境

返回值:

  • 返回locale对象当前与流缓冲区关联的对象。

                     获取区

in_avail

获得获取区中立即可用的字符数

snextc

令输入序列前进,读取一个字符而不再次前进

sgetc

从输入序列读取一个字符,而不令序列前进

sgetn

调用 xsgetn()

sbumpc

从输入序列读取一个字符并令序列前进到下一个位置

in_avail

streamsize in_avail();

功能:

  • 获取可读取的字符数
  • 此值取决于get指针(是否有直接可用的读取位置gptr

返回值:

  • 可读取的字符数
  • 值-1表示没有其他字符可用

 

// get file size using pubseekoff
#include <iostream>     // std::cout, std::streambuf, std::streamsize
#include <fstream>      // std::ifstream

int main () {
  std::ifstream ifs ("test.txt");
  if (ifs.good()) {
    std::streambuf* pbuf = ifs.rdbuf();
    char c; ifs >> c;
    std::streamsize size = pbuf->in_avail();
    std::cout << "first character in file: " << c << '\n';
    std::cout << size << " characters in buffer after it\n";
  }
  ifs.close();

  return 0;
}
 编辑并运行

snextc、sbumpc、sgetc、sgetn

int_type sbumpc();

功能:

  • sbumpc:获取当前字符并前进到下一个位置

返回值:

  • 返回受控输入序列当前位置处的字符,并将位置指示器前进到下一个字符。

请注意,尽管类似,但以下成员函数具有不同的行为:

成员功能描述
sgetc()返回当前位置的字符。
sbumpc()返回当前位置的字符,并将当前位置前进到下一个字符。
snextc()将当前位置前进到下一个字符并返回下一个字符。
int_type sgetc ();
int_type snextc();

功能:

  • sgetc:从输入序列中读取一个字符
  • snextc:前进到下一个位置并读取一个字符
  • 如果输入序列读取位置不可用,则返回underflow()

返回值:

  • get指针指向的字符的值
streamsize sgetn(char_type * s,streamsize n);

功能:

  • sgetn:获取字符序列

返回值:

  • 成功读取的字符数。如果小于count输入序列,则结束。
#include <iostream>     // std::cout, std::streambuf
#include <fstream>      // std::ifstream

效果:逐个字符读取文件内容并输入
int main () {
  std::ifstream istr ("test.txt");
  if (istr) {
    std::streambuf * pbuf = istr.rdbuf();
    while ( pbuf->sgetc() != std::streambuf::traits_type::eof() )
    {
      char ch = pbuf->sbumpc();
      std::cout << ch;
    }
    istr.close();
  }
  return 0;
}

 

 

#include <iostream>
#include <sstream>
 
int main()
{
    std::stringstream stream("Hello, world");
    std::cout << "sgetc() returned '" << (char)stream.rdbuf()->sgetc() << "'\n";
    std::cout << "peek() returned '" << (char)stream.peek() << "'\n";
    std::cout << "get() returned '" << (char)stream.get() << "'\n";
}

#include <iostream>
#include <sstream>

int main()
{
    std::stringstream stream("Hello, world");
    std::cout << "sgetc() returned '" << (char)stream.rdbuf()->snextc() << "'\n";
}

 

#include <iostream>     // std::cout, std::streambuf
#include <fstream>      // std::ifstream

// 本示例使用其流缓冲区将整个文件读入缓冲区,然后将其写入标准输出。
int main () {
    std::ifstream istr ("test.txt");
    if (istr) {
        std::streambuf * pbuf = istr.rdbuf();

        std::streamsize size = pbuf->pubseekoff(0,istr.end);
        pbuf->pubseekoff(0,istr.beg);       // rewind

        char *contents = new char[size];

        pbuf->sgetn(contents, size);

        istr.close();

        std::cout.write(contents, size);
    }
    return 0;
}
          放置区

sputc

写一个字符到放置区域,并令 next 指针前进

sputn

调用 xsputn()

std::basic_streambuf::sputc、std::basic_streambuf::sputn

int_type sputc( char_type ch );

功能:

  • sputc:将一个字符写入输出序列。

  • sputn:将n个字符写入到输出序列

  • 如果输出序列写位置不可用(缓冲区已满),则调用overflow(ch)

#include <iostream> 
#include <sstream> 
 
int main ()
{ 
    std :: ostringstream s ; 
    s.rdbuf ()- > sputc ('a'); 
    std :: cout  << s.str() <<  ' \ n ' ; 
}

#include <iostream>     // std::streambuf
#include <fstream>      // std::ofstream

int main () {
  const char sentence[]= "Sample sentence";

  std::ofstream ostr ("test.txt");
  if (ostr) {
    std::streambuf * pbuf = ostr.rdbuf();
    pbuf->sputn (sentence,sizeof(sentence)-1);
    ostr.close();
  }

  return 0;
}

 

                           回放

sputbackc

在输入序列中放回一个字符

sungetc

回移一位输出序列中的下一位置指针

 

std::basic_streambuf::sputbackc

int_type sputbackc(char_type c);

功能:将字符放回获取区域

#include <iostream>

int main()
{
    char ch;
    std::streambuf  *pbuf = std::cin.rdbuf();

    std::cout << "Please, enter some letters and then a number: ";
    do {
        ch = pbuf->sbumpc();

        if ( (ch>='0') && (ch <='9') )
        {
            pbuf->sputbackc(ch);
            long n;
            std::cin >> n;
            std::cout << "You entered number " << n << '\n';
        }

    } while ( ch != std::streambuf::traits_type::eof() );

    return 0;
}

本示例从标准输入中一个接一个地获取字符。找到第一个数字后,反击被调用以将流中的位置恢复到该数字,以便使用提取运算符将其提取为数字的一部分>>

std::basic_streambuf::sungetc

int_type sungetc();

功能:

  • 如果在获取区域有一个后备仓位(gptr  > eback ),然后递减下一个指针(gptr())并返回它现在指向的字符。

    如果没有备用位置,则在可能的情况下调用pbackfail()备份输入序列。

    I / O流功能basic_istream :: unget是根据此功能实现的

#include <iostream>
#include <sstream>
 
int main()
{
    std::stringstream s("abcdef"); // gptr() points to 'a'
    char c1 = s.get(); // c = 'a', gptr() now points to 'b' 
    char c2 = s.rdbuf()->sungetc(); // same as s.unget(): gptr() points to 'a' again 
    char c3 = s.get(); // c3 = 'a', gptr() now points to 'b'
    char c4 = s.get(); // c4 = 'b', gptr() now points to 'c'
    std::cout << c1 << c2 << c3 << c4 << '\n';
 
    s.rdbuf()->sungetc();  // back to 'b'
    s.rdbuf()->sungetc();  // back to 'a'
    int eof = s.rdbuf()->sungetc();  // nothing to unget: pbackfail() fails
    if (eof == EOF)
            std::cout << "Nothing to unget after 'a'\n";
}

              寻位

setbufpubseekoff、pubseekoff

若容许则以用户定义数组替换缓冲区

seekoff

用相对寻址重定位输入序列、输出序列或两者中的下一位置指针

seekpos

用绝对寻址重定位输入序列、输出序列或两者中的下一位置指针

sync

将缓冲与关联的字符序列同步

std::basic_streambuf::pubsetbuf、std::basic_streambuf::setbuf

basic_streambuf<CharT, Traits>* pubsetbuf( char_type* s, std::streamsize n )           (1)	

protected:
virtual basic_streambuf<CharT, Traits>* setbuf( char_type* s, std::streamsize n )      (2)

功能:设置相对于其他位置的输入或者输出序列的位置指示器

1) 调用最终派生类上的 setbuf(s, n)

2) 此函数的基类版本无效果。派生类可覆写此函数,以允许移除或替换受控制字符序列(缓冲区)为用户提供的数组,或为任何实现特定的目的。

参数

s-指向用户提供的缓冲区中首个 CharT 的指针
n-用户提供缓冲区中的 CharT 元素数

返回值

1) setbuf(s, n) 的返回值

2) this

#include <iostream>     // std::cout, std::streambuf
#include <fstream>      // std::fstream

int main () {
    std::fstream filestr ("test.txt");
    if (filestr) {
        std::streambuf* pbuf = filestr.rdbuf();
        long size = pbuf->pubseekoff(0,std::fstream::beg);
        std::cout << "The file size is " << size << " characters.\n";
        filestr.close();
    }

    return 0;
}

#include <fstream>
#include <iostream>
#include <string>
//为读取提供 10k 缓冲区。 Linux 上,可用 strace 工具观察实际读取的字节数
int main()
{
    int cnt = 0;
    std::ifstream file;
    char buf[1024*10 + 1];

    file.rdbuf()->pubsetbuf(buf, sizeof buf);

    file.open("/usr/share/dict/words");

    for (std::string line; getline(file, line);) {
        cnt++;
    }

    std::cout << cnt << '\n';
}

std::basic_streambuf::pubseekoffstd::basic_streambuf::seekoff

pos_type pubseekoff( off_type off, std::ios_base::seekdir dir,
                     std::ios_base::openmode which = ios_base::in | ios_base::out );    (1)	
protected:
virtual pos_type seekoff( off_type off, std::ios_base::seekdir dir,
                          std::ios_base::openmode which = ios_base::in | ios_base::out );  (2)	

相对某其他位置,设置输入/输出序列的位置指示器。

1) 调用最终导出类的 seekoff(off, dir, which)

2) 此函数的基类版本无效果。导出类可覆写此函数以允许位置指示器的相对寻位。

参数

off要设置位置指示器到的相对位置。
dir
定义要应用相对偏移到的基位置。它能为下列常量之一:
常量解释
beg流的开始
end流的结尾
cur流位置指示器的当前位置
which
定义输入和/或输出序列何者有影响。它能为下列常量之一或其组合:
常量解释
in影响输入序列
out影响输出序列

 

#include <iostream>     // std::cout, std::streambuf
#include <fstream>      // std::fstream

int main () {

    std::fstream filestr ("test.txt");
    if (filestr) {
        std::streambuf* pbuf = filestr.rdbuf();
        long size = pbuf->pubseekoff(0,filestr.end);  // get size
        if (size>20) {
            char buffer[11];
            // change position to the 10th character
            pbuf->pubseekpos(10);
            // read 10 characters
            pbuf->sgetn (buffer,10);
            // append null character to string
            buffer[10]=0;
            std::cout << buffer << '\n';
        }
        filestr.close();
    }
    return 0;
}

效果:读取并打印文件的第11至20个字符

 

std::basic_streambuf::sync、std::basic_streambuf::pubsync

int pubsync();       (1)
 
protected:
virtual int sync();   (2)

功能:

(1) 同步流缓冲区

(2) 此函数的基类版本无效果。导出类可覆写此函数以允许将底层设备与缓冲区同步。

返回值:

  • 默认定义 同步 在 流缓冲总是返回零,表示成功。
  • 派生类可以覆盖此默认行为,并最终返回-1以指示失败。
// pubsync member
#include <iostream>     // std::cout, std::streambuf
#include <fstream>      // std::ofstream

int main () {
  std::ofstream ostr ("test.txt");
  if (ostr) {
    std::streambuf * pbuf = ostr.rdbuf();

    pbuf->sputn ("First sentence\n",15);
    pbuf->pubsync();
    pbuf->sputn ("Second sentence\n",16);

    ostr.close();
  }
  return 0;
}

              获取区

showmanyc

[虚]

若已知,则获得关联输入序列中可用于输入的字符数

underflow

[虚]

从关联输入序列读取字符到获取区

uflow

[虚]

从输入序列读取字符到获取区,并令下一位置指针前进

xsgetn

[虚]

从输入序列读取多个字符

eback、gptr、egptr

返回指向获取区起始、当前字符和末尾的指针

gbump

令输出序列中的下一位置指针前进

setg

重定位输出序列的起始、下一位置和终止指针

-

                                    放置区

xsputn

[虚]

将多个字符写到输出序列

overflow

[虚]

从放置区写入字符到关联的输出序列

pbase、pptre、pptr

返回指向放置区的起始、当前字符和末尾的指针

pbump

令输出序列中的下一位置指针前进

setp

重定位输出序列的起始、下一位置和终止指针

std::basic_streambuf::pbump

#include <iostream>
#include <string>
#include <fstream>
 
struct showput_streambuf : std::filebuf
{
    using std::filebuf::pbump; // expose protected
    std::string showput() const {
        return std::string(pbase(), pptr());
    }
};
 
int main()
{
    showput_streambuf mybuf;
    mybuf.open("test.txt", std::ios_base::out);
    std::ostream str(&mybuf);
    str << "This is a test" << std::flush << "1234";
    std::cout << "The put area contains: " << mybuf.showput() << '\n';
    mybuf.pbump(10);
    std::cout << "after pbump(10), it contains " << mybuf.showput() << '\n';
}

std::basic_streambuf::setp

void setp (char_type* new_pbase, char_type* new_epptr);

设置指针的值,这些指针定义受控输出序列缓冲部分的边界(pbase and epptr).

置入指针pptr)会自动设置为该序列的开头。
这是一个受保护的成员,其他成员函数可以调用该成员来更改描述受控输出序列的缓冲部分的数组。

#include <iostream>
#include <array>
#include <streambuf>

// Buffer for std::ostream implemented by std::array
template<std::size_t SIZE, class CharT = char>
class ArrayedStreamBuffer : public std::basic_streambuf<CharT>
{
public:
    using Base = std::basic_streambuf<CharT>;
    using char_type = typename Base::char_type;

    ArrayedStreamBuffer() : buffer_{} // value-initialize buffer_ to all zeroes
    {
        Base::setp(buffer_.begin(), buffer_.end()); // set std::basic_streambuf
        // put area pointers to work with 'buffer_'
    }

    void print_buffer()
    {
        for (const auto& i: buffer_) {
            if (i == 0) {
                std::cout << "\\0";
            } else {
                std::cout << i;
            }
            std::cout << ' ';
        }
        std::cout << '\n';
    }

private:
    std::array<char_type, SIZE> buffer_;
};

int main () {
    ArrayedStreamBuffer<10> streambuf;
    std::ostream stream(&streambuf);

    stream << "hello";
    stream << ",";

    streambuf.print_buffer();

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值