C++的流分析basic_filebuf

 
文件流要使用的 io 基础类的枚计类型
 
class ios_base {
public :
  enum __seekdir {
    beg = 0x01,                   // 开始
    cur = 0x02,           // 当前
    end = 0x04           // 结尾
 };
  enum __iostate {
    goodbit = 0x00,
    badbit  = 0x01,
    eofbit  = 0x02,
    failbit = 0x04
 };
  enum __openmode {
    app     = 0x01,
    ate     = 0x02,
    binary = 0x04,
    in      = 0x08,
    out     = 0x10,
    trunc  = 0x20
 };
};
 
 
_Filebuf_base 文件缓冲基类
 
class _Filebuf_base {
protected :
 _Filebuf_base();
 
 // 打开和关闭文件缓冲区
  bool _M_open( const char *, ios_base :: openmode , long __protection);
  bool _M_open( const char *, ios_base :: openmode );
  bool _M_open( int __id);
  bool _M_close();
 
protected :                    
 // 低级 I/O 读写
  ptrdiff_t _M_read( char * __buf,  ptrdiff_t __n);
  bool _M_write( char * __buf,  ptrdiff_t __n);
        
 // 设置文件偏移位置和文件大小
  streamoff _M_seek( streamoff __offset, ios_base :: seekdir __dir);
  streamoff _M_file_size ();
 
protected :               
 // 内存映射 I/O
  void * _M_mmap( streamoff __offset, streamoff __len);
  void _M_unmap( void * __mmap_base, streamoff __len);
 
protected :
  // Returns a value n such that, if pos is the file pointer at the
  // beginning of the range [first, last), pos + n is the file pointer at
  // the end. On many operating systems n == __last - __first.
  streamoff _M_get_offset( char * __first, char * __last);
 
  // Returns true if we're in binary mode or if we're using an OS or file
  // system where there is no distinction between text and binary mode.
  bool _M_in_binary_mode() const ;
 
protected :
#ifdef _MSC_VER
  int _M_hFileMappingObject; // 映射对象句柄
#endif
  int _M_file_id;       // 文件句柄
  ios_base :: openmode _M_openmode;    // 打开模式
  int _M_page_size; // 页的大小
 
  bool _M_is_open      : 1;
  bool _M_should_close : 1;
  bool _M_regular_file : 1;
};
 
 
 
文件缓冲区类
template < class _CharT , class _Traits >
class basic_filebuf : public basic_streambuf < _CharT , _Traits >,
                      private _Filebuf_base
{
public :                         // Types.
  typedef _CharT                    char_type ;
  typedef typename _Traits :: int_type       int_type ;
  typedef typename _Traits :: pos_type     pos_type ;
  typedef typename _Traits :: off_type       off_type ;
  typedef _Traits                      traits_type ;
 
  typedef typename _Traits :: state_type   _State_type ;
  typedef basic_streambuf < _CharT , _Traits > _Base ;
 
public basic_filebuf ();
 ~ basic_filebuf ();
 
public :
 // 关闭和打开文件
  bool is_open () const ;
  basic_filebuf * open ( const char *, ios_base :: openmode );
 
 // 扩展版本 open()
  basic_filebuf * open ( const char *, ios_base :: openmode , long __protection );
  basic_filebuf * open ( int __id );
  basic_filebuf * close ();
 
protected :
 // basic_streambuf 基类的重载的虚函数
  virtual streamsize showmanyc ();
  virtual int_type underflow ();
  virtual int_type pbackfail ( int_type = _Traits :: eof ());
  virtual int_type overflow ( int_type = _Traits :: eof ());
  virtual basic_streambuf < _CharT , _Traits >* setbuf ( char_type *, streamsize );
  virtual pos_type seekoff ( off_type , ios_base :: seekdir ,
                           ios_base :: openmode = ios_base :: in | ios_base :: out );
  virtual pos_type seekpos ( pos_type ,
                           ios_base :: openmode = ios_base :: in | ios_base :: out );
  virtual int sync ();
  virtual void imbue ( const locale &);
 
private :
// 内部帮助函数
 
// 模式
  void _M_exit_putback_mode ();
  bool _M_switch_to_input_mode ();
  void _M_exit_input_mode ();
  bool _M_switch_to_output_mode ();
 
  int_type _M_input_error ();
  int_type _M_underflow_aux ();
 
  friend class _Noconv_output< _Traits >;
  friend class _Noconv_input< _Traits >;
  friend class _Underflow< basic_filebuf < _CharT , _Traits > >;
 
  int_type _M_output_error ();
  bool _M_unshift ();
 
 // 分配缓存区
  bool _M_allocate_buffers ( _CharT * __buf , int __n );
  bool _M_allocate_buffers ();
  void _M_deallocate_buffers ();
 
 // 定位缓冲区
  pos_type _M_seek_return ( off_type , _State_type );
  bool _M_seek_init ( bool __do_unshift );
 
 // 设置字符集转换
  void _M_setup_codecvt ( const locale &);
 
private :
 // 文件缓冲区用户看到的内部字符缓冲区 :
  _CharT * _M_int_buf ;
  _CharT * _M_int_buf_EOS ;
 
  // 对应扩展文件字符的扩展缓冲区
  char * _M_ext_buf ;
  char * _M_ext_buf_EOS ;
 
 // 对应内部缓冲区的开始状态
  _State_type _M_state ;
 
private :              
// 只在输入模式使用的数据成员
 // [_M_ext_buf, _M_ext_buf_converted] 包含了扩展字符对应内部缓冲区
 // [_M_ext_buf_converted, _M_ext_buf_end] 包含已经读入扩展缓冲区当没有转换内部 equence.
  char * _M_ext_buf_converted ;
  char * _M_ext_buf_end ;
 
 // 类似 _M_state 对应内部缓冲区结尾状态
  _State_type _M_end_state ;
 
 // 除非使用内存映射文件 , 否则为空指针
  void * _M_mmap_base ;
  streamoff _M_mmap_len ;
 
private :                       
// 只在输出模式使用的数据成员
  _CharT * _M_saved_eback ;
  _CharT * _M_saved_gptr ;
  _CharT * _M_saved_egptr ;
 
  enum { _S_pback_buf_size = 8 };
  _CharT _M_pback_buf [ _S_pback_buf_size ];
 
private :                       
// 本地化信息 ( 不关心 )
  typedef codecvt < _CharT , char , _State_type > _Codecvt ;
  const _Codecvt * _M_codecvt ;
 
  int _M_width ;                   // 编码宽度 (if constant), else 1
  int _M_max_width ;               // 单个字符最低宽度
  bool _M_constant_width : 1;
  bool _M_always_noconv  : 1;
 
private :                       
// 模式标记
  bool _M_int_buf_dynamic : 1;      // True 内部缓冲区是堆分配
                                  // false 由用户提供
  bool _M_in_input_mode     : 1;
  bool _M_in_output_mode    : 1;
  bool _M_in_error_mode     : 1;
  bool _M_in_putback_mode  : 1;
};
 
 
 
这个成员必须流在执行任何 IO 操作之前调用 , 否则没有作用
// __buf == 0 && __n == 0 means to make ths stream unbuffered.
// __buf != 0 && __n > 0 means to use __buf as the stream's internal
// buffer, rather than the buffer that would otherwise be allocated
// automatically. __buf must be a pointer to an array of _CharT whose
// size is at least __n.
template < class _CharT , class _Traits >
basic_streambuf < _CharT , _Traits >*
basic_filebuf < _CharT , _Traits >:: setbuf ( _CharT * __buf , streamsize __n )
{
  if (!_M_in_input_mode &&! _M_in_output_mode && !_M_in_error_mode &&
      _M_int_buf == 0) {
    if ( __buf == 0 && __n == 0)
      _M_allocate_buffers(0, 1);
    else if ( __buf != 0 && __n > 0)
      _M_allocate_buffers( __buf , __n );
 }
  return this ;
}
 
seekoff()
// __off 是偏移量 ( 整型 ), __whence 是方向 ( 枚计类型 ) 从开始 , 当前 , 结尾偏移 ), 该函数主要还是调用另外一个方法基类的函数 _M_seek 实现 , _M_seek 则调用 lseek 系统函数实现
 
_M_seek 定义如下:参数(偏移量和方向),放回lseek的返回值
_M_seek(streamoff offset, ios_base::seekdir dir)
 
template < class _CharT , class _Traits >
typename basic_filebuf < _CharT , _Traits >:: pos_type
basic_filebuf < _CharT , _Traits >:: seekoff ( off_type __off ,
                                 ios_base :: seekdir __whence,
                                 ios_base :: openmode /* dummy */ )
{
  if ( this -> is_open () &&
( __off == 0 || (_M_constant_width && this ->_M_in_binary_mode())))
{
         // 定位初始化
    if (!_M_seek_init( __off != 0 || __whence != ios_base :: cur ))
      return pos_type (-1);
 
// 从到头或尾定位 , 不管是否输入模式
    if (__whence == ios_base :: beg || __whence == ios_base :: end )
      return _M_seek_return(this->_M_seek(_M_width * __off, __whence),
                            _State_type());
 
// 从当前位置定位 , 如果在输入模式问题就复杂化
else if (__whence == ios_base :: cur ) {
      if (!_M_in_input_mode)
        return _M_seek_return(this->_M_seek(_M_width * __off, __whence),
_State_type());
 
         // 使用了内存映射 .
      else if (_M_mmap_base != 0) {
         // __off is relative to gptr(). We need to do a bit of arithmetic
        // to get an offset relative to the external file pointer.
        streamoff __adjust = this -> gptr () - ( _CharT *) _M_mmap_base;
       
        return _M_seek_return( this ->_M_seek( __off + __adjust - _M_mmap_len,
                                            ios_base :: cur ),
                              _State_type());
}
// 使用固定字符宽度
      else if (_M_constant_width) { // Get or set the position. 
        streamoff __iadj = _M_width * ( this -> gptr () - this -> eback ());
        // Compensate for offset relative to gptr versus offset relative
        // to external pointer. For a text-oriented stream, where the
        // compensation is more than just pointer arithmetic, we may get
        // but not set the current position.
        if (__iadj <= _M_ext_buf_end - _M_ext_buf) {
          streamoff __eadj =
            _M_get_offset(_M_ext_buf, _M_ext_buf + __iadj) -
            _M_get_offset(_M_ext_buf, _M_ext_buf_end);
          streamoff __cur = this ->_M_seek( __off , ios_base :: cur );
          if (__cur != -1 && __cur + __eadj >= 0)
            return _M_seek_return(__cur + __eadj, _State_type());
          else
            return pos_type (-1);
        }
        else
          return pos_type (-1);
}
// 使用编码宽度
      else {                    // Get the position. Encoding is var width.
        // Get position in internal buffer.
        ptrdiff_t __ipos = this -> gptr () - this -> eback ();
       
        // Get corresponding position in external buffer.
        _State_type __state = _M_state;
        int __epos = _M_codecvt-> length (__state, _M_ext_buf, _M_ext_buf_end,
                                        __ipos);
 
        // Sanity check (expensive): make sure __epos is the right answer.
        _State_type __tmp_state = _M_state;
        _Filebuf_Tmp_Buf< _CharT , _Traits > __buf(__ipos);
        _CharT * __ibegin = __buf._M_ptr;
         _CharT * __inext = __ibegin;
 
        const char * __dummy ;
        typename _Codecvt:: result __status
          = _M_codecvt-> in (__tmp_state,
                           _M_ext_buf, _M_ext_buf + __epos, __dummy ,
                           __ibegin, __ibegin + __ipos, __inext);
        if (__status != _Codecvt:: error &&
            (__status == _Codecvt:: noconv ||
             (__inext == __ibegin + __ipos &&
              equal ( this -> gptr (), this -> eback (), __ibegin,
                    _Eq_traits< traits_type >())))) {
          // Get the current position (at the end of the external buffer),
          // then adjust it. Again, it might be a text-oriented stream.
          streamoff __cur = this ->_M_seek(0, ios_base :: cur );
          streamoff __adj =
             this ->_M_get_offset(_M_ext_buf, _M_ext_buf + __epos) -
            this ->_M_get_offset(_M_ext_buf, _M_ext_buf_end);
          if (__cur != -1 && __cur + __adj >= 0)
            return _M_seek_return(__cur + __adj, __state);
          else
            return pos_type (-1);
        }
        else                     // We failed the sanity check.
          return pos_type (-1);
      }
    }
    else                         // Unrecognized value for __whence.
      return pos_type (-1);
 }
  else
    return pos_type (-1);
}
 
 
seekpos() 该函数桶上述的函数类似 , 还是调用 _M_seek 函数来实现 , 不同的是从开始偏移
{ … _M_seek( __off , ios_base :: beg ) …}
 
template < class _CharT , class _Traits >
typename basic_filebuf < _CharT , _Traits >:: pos_type
basic_filebuf < _CharT , _Traits >:: seekpos ( pos_type __pos,
                                  ios_base :: openmode /* dummy */ )
{
  if ( this -> is_open ()) {
    if (!_M_seek_init( true ))
      return pos_type (-1);
 
    streamoff __off = off_type (__pos);
    if ( __off != -1 && this ->_M_seek( __off , ios_base :: beg ) != -1) {
      _M_state = __pos. state ();
      return _M_seek_return( __off , __pos. state ());
    }
    else
      return pos_type (-1);
 }
  else
    return pos_type (-1);
}
 
 
 
 
 
// Wrapper for lseek or the like.
streamoff _Filebuf_base::_M_seek( streamoff offset , ios_base :: seekdir dir )
{
  streamoff result = -1;
 
  int whence;
 
  switch ( dir ) {
  case ios_base :: beg :
    if ( offset < 0 || offset > _M_file_size())
      return -1;
    whence = SEEK_SET ;
    break ;
  case ios_base :: cur :
    whence = SEEK_CUR ;
    break ;
  case ios_base :: end :
    if ( offset > 0 || - offset > _M_file_size())
      return -1;
    whence = SEEK_END ;
    break ;
  default :
    return streamoff (-1);
 }
 
  result = LSEEK(_M_file_id, offset , whence);
 
  return result ;
}
 
 
 
// Helper functiosn for seek and imbue
 
template < class _CharT, class _Traits>
typename basic_filebuf <_CharT, _Traits>:: pos_type
basic_filebuf <_CharT, _Traits>::_M_seek_return( off_type __off,
                                               _State_type __state) {
  if (__off != -1) {
    if (_M_in_input_mode)
      _M_exit_input_mode();
    _M_in_output_mode = false ;
    _M_in_putback_mode = false ;
    _M_in_error_mode = false ;
    this -> setg (0, 0, 0);
    this -> setp (0, 0);
 }
 
  pos_type __result(__off);
 __result. state (__state);
  return __result;
}
 
 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值