美文网首页
C++: streambuf

C++: streambuf

作者: 圣地亚哥_SVIP | 来源:发表于2020-11-26 10:59 被阅读0次

    streambuf定义了对流缓冲区操作的接口,主要分为输出缓冲流和输入缓冲流。streambuf有两种用法,一是直接使用各个接口,二是继承并实现新的I/O channels。

    1. 输出缓冲流:
    • pbase(): put base,输出缓冲流的首指针。
    • pptr(): put pointer,当前可写位置
    • epptr(): end put pointer,输出缓冲流的尾指针+1,即one past the last character。

    函数:
    setp(char new_pbase, char new_epptr)**
    注:设置pbase,pptr,epptr三个指针的位置:

    • pbase()=new_pbase;
    • pptr()=bew_pbase;
    • epptr()=new_epptr;

    pbump(int offset)
    注: 移动pptr offset个位置。当我们写入num个数据,pbump(num)。

    overflow
    当缓冲区满时的操作;
    pptr() == epptr()

    2. 输入缓冲流:
    • eback(): 指向输入缓冲流的首指针
    • gptr(): 当前输入缓冲流的位置
    • egptr(): 输入缓冲流的末尾
    • gbump(): 移动gptr
    • setg(): 设置eback/gptr/egptr的位置

    underflow()
    当无缓冲区数据可读时。
    cond: gptr()=egptr()

    setg
    setg (eback_base,new_gptr, new_egptr)
    分别设置:

    • eback
    • gptr
    • egptr
    3. 基于streambuf自定义一个输入输出缓冲流

    prebufferstream.hpp:

    /*  Author: zhangwen1@unionpay.com */
    /*  Date: 2020-11-24               */
    
    /*
     * Provide Custom Streambufeer Example 
    */ 
    
    #ifndef PREBUFFERSTREAM_HPP
    #define PREBUFFERSTREAM_HPP
    
    #include <streambuf>
    #include <cstdio>
    #include <exception>
    
    class prebuffer: public std::streambuf{
    
    public:
      typedef std::char_traits<char> traits_ty;
      typedef traits_ty::int_type int_type;
      typedef traits_ty::pos_type pos_type;
      typedef traits_ty::off_type off_type;
    
    private:
      int m_mode;
      int m_filedes;
    
      static const int s_buf_size = 4092;
      static const int s_pback_size = 4;
      char buffer[s_buf_size];
    
      void init(int fd, int om, bool throw_exception);
    
      int flushoutput();
    
    public:
    
      prebuffer(int fd, int om, bool throw_exception=false);
      prebuffer(const prebuffer&)=delete;
      prebuffer& operator=(const prebuffer&)=delete;
      prebuffer(prebuffer&&)=delete;
      prebuffer& operator=(prebuffer&&)=delete;
    
      ~prebuffer(){close();}
    
      virtual int_type overflow(int_type c) override;
      virtual int_type underflow() override;
    
      bool is_open() const { return m_filedes >= 0; }
    
      void close();
      virtual int sync() override;
    
      std::string get_str(){
        return std::string(buffer,this->pptr()-buffer);
      }
    
    };
    
    
    class FileError: public std::exception{
      const char* what(void) const throw(){
        return "Invaild fd";
      }
    };
    
    #endif
    

    prebufferstream.cc:

    #include "prebufferstream.hpp"
    
    #include <iostream>
    #include <unistd.h>
    #include <cstring>
    
    void prebuffer::init(int fd, int om, bool throw_exception){
      m_filedes = fd;
      if (m_filedes > 0){
        m_mode = om;
      }
      if (throw_exception && !is_open()){
          throw FileError();
      }
      setg(buffer+s_pback_size,
           buffer+s_pback_size,
           buffer+s_pback_size);
      setp(buffer,
           buffer+s_buf_size-1);
    }
    
    prebuffer::prebuffer(int fd, int om, bool throw_exception){
      init(fd,om,throw_exception);
    }
    
    void prebuffer::close(){
      if (is_open()){
        this->sync();
        m_mode = 0;
        m_filedes = -1;
      }
    }
    
    prebuffer::int_type prebuffer::underflow(){
    
      if (gptr() < egptr()){
        return static_cast<unsigned char>(*gptr());
      }
      int num_putback=0;
      if (s_pback_size > 0){
        num_putback = gptr()-eback();
        if (num_putback > s_pback_size){
          num_putback = s_pback_size;
        }
        std::memcpy(buffer+s_pback_size-num_putback,gptr()-num_putback,num_putback);
      }
    
      const int num = ::read(m_filedes,buffer+s_pback_size,s_buf_size-s_pback_size);
    
      if (num <= 0){return EOF;}
      setg(buffer+s_pback_size-num_putback,buffer+s_pback_size,buffer+s_pback_size+num);
    
      return static_cast<unsigned char>(*gptr());
    
    }
    
    prebuffer::int_type prebuffer::overflow(int_type c){
      std::cout<<"Overflow Happend"<<std::endl;
      if (!(m_mode & std::ios::out) || !is_open()) return EOF;
      if (c != EOF){
        *pptr() = c;
        pbump(1);
      }
      if (flushoutput() == EOF)
        {
          return -1; 
        }
    
      return c;
    }
    
    int prebuffer::flushoutput(){
      if (!(m_mode & std::ios::out) || !is_open()) return EOF;
      size_t num = pptr()-pbase();
      if (::write(m_filedes,buffer,num) == -1){
        return EOF;
      }
      pbump(-num);
      return num;
    }
    
    int prebuffer::sync(){
      if (flushoutput() == EOF){
        return -1;
      }
      return 0;
    }
    

    测试, main.cc:

    #include "prebufferstream.hpp"
    #include <fcntl.h> 
    #include <ostream>
    #include <istream>
    #include <unistd.h>
    #include <iostream>
    
    int main(int argc,char* argv[]){
    
      std::string file_name1 = "test";
      std::string file_name2 = "intest";
      int fdout;
      int fdin;
      if ((fdout=open(file_name1.c_str(),O_RDWR | O_CREAT | O_APPEND)) < 0){
        std::cout<<"ERROR Open File"<<std::endl;
      }
      if ((fdin=open(file_name2.c_str(),O_RDONLY | O_CREAT | O_APPEND)) < 0){
        std::cout<<"ERROR Open File"<<std::endl;
      }
    
    
      prebuffer ot{fdout,std::ios::out};
      prebuffer it{fdin,std::ios::in};
      std::ostream dout(&ot);
      std::istream dint(&it);
      dout<<1<<2<<3<<4<<5<<"\n";
    
      std::cout<<ot.get_str()<<std::endl;
    
      ot.sync();
      int line;
      while (dint>>line){
        std::cout<<line<<" ";
      }
    
      close(fdout);
      close(fdin);
    
      return 0;
    }
    

    相关文章

      网友评论

          本文标题:C++: streambuf

          本文链接:https://www.haomeiwen.com/subject/sqjaiktx.html