C++的流分析basic_filebuf


文件流要使用的io基礎類的枚計類型
 
classios_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(constchar*, ios_base::openmode, long __protection);
 bool _M_open(constchar*, 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>
classbasic_filebuf : publicbasic_streambuf<_CharT, _Traits>,
                      private _Filebuf_base
{
public:                         // Types.
 typedef_CharT                   char_type;
 typedeftypename_Traits::int_type       int_type;
 typedeftypename_Traits::pos_type     pos_type;
 typedeftypename_Traits::off_type       off_type;
 typedef_Traits                    traits_type;
 
 typedeftypename_Traits::state_type  _State_type;
 typedefbasic_streambuf<_CharT, _Traits> _Base;
 
publicbasic_filebuf();
 ~basic_filebuf();
 
public:
 // 關閉和打開文件
 boolis_open() const;
 basic_filebuf* open(constchar*, ios_base::openmode);
 
 // 擴展版本open()
 basic_filebuf* open(constchar*, ios_base::openmode, long__protection);
 basic_filebuf* open(int__id);
 basic_filebuf* close();
 
protected:
 // basic_streambuf基類的重載的虛函數
 virtualstreamsizeshowmanyc();
 virtualint_typeunderflow();
 virtualint_typepbackfail(int_type = _Traits::eof());
 virtualint_typeoverflow(int_type = _Traits::eof());
 virtualbasic_streambuf<_CharT, _Traits>* setbuf(char_type*, streamsize);
 virtualpos_typeseekoff(off_type, ios_base::seekdir,
                           ios_base::openmode = ios_base::in | ios_base::out);
 virtualpos_typeseekpos(pos_type,
                           ios_base::openmode = ios_base::in | ios_base::out);
 virtualintsync();
 virtualvoidimbue(constlocale&);
 
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();
 
 friendclass _Noconv_output<_Traits>;
 friendclass _Noconv_input<_Traits>;
 friendclass _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(constlocale&);
 
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:                       
// 本地化信息(不關心)
 typedefcodecvt<_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);
    elseif (__buf != 0 && __n > 0)
      _M_allocate_buffers(__buf, __n);
 }
 returnthis;
}
 
seekoff()
// __off是偏移量(整型), __whence是方向(枚計類型)從開始,當前,結尾偏移),該函數主要還是調用另外一個方法基類的函數_M_seek實現, _M_seek則調用lseek系統函數實現
 
_M_seek定義如下:參數(偏移量和方向),放回lseek的返回值
_M_seek(streamoff offset, ios_base::seekdir dir)
 
template <class_CharT, class_Traits>
typenamebasic_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))
      returnpos_type(-1);
 
//從到頭或尾定位,不管是否輸入模式
    if (__whence == ios_base::beg || __whence == ios_base::end)
      return _M_seek_return(this->_M_seek(_M_width * __off, __whence),
                            _State_type());
 
// 從當前位置定位,如果在輸入模式問題就複雜化
elseif (__whence == ios_base::cur) {
      if (!_M_in_input_mode)
        return _M_seek_return(this->_M_seek(_M_width * __off, __whence),
_State_type());
 
         // 使用了內存映射.
      elseif (_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());
}
// 使用固定字符寬度
      elseif (_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
            returnpos_type(-1);
        }
        else
          returnpos_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;
 
        constchar* __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
            returnpos_type(-1);
        }
        else                    // We failed the sanity check.
          returnpos_type(-1);
      }
    }
    else                        // Unrecognized value for __whence.
      returnpos_type(-1);
 }
 else
    returnpos_type(-1);
}
 
 
seekpos()該函數桶上述的函數類似,還是調用_M_seek函數來實現,不同的是從開始偏移
{ … _M_seek(__off, ios_base::beg) …}
 
template <class_CharT, class_Traits>
typenamebasic_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))
      returnpos_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
      returnpos_type(-1);
 }
 else
    returnpos_type(-1);
}
 
 
 
 
 
// Wrapper for lseek or the like.
streamoff _Filebuf_base::_M_seek(streamoffoffset, ios_base::seekdirdir)
{
 streamoffresult = -1;
 
 int whence;
 
 switch(dir) {
 caseios_base::beg:
    if (offset < 0 || offset > _M_file_size())
      return -1;
    whence = SEEK_SET;
    break;
 caseios_base::cur:
    whence = SEEK_CUR;
    break;
 caseios_base::end:
    if (offset > 0 || -offset > _M_file_size())
      return -1;
    whence = SEEK_END;
    break;
 default:
    returnstreamoff(-1);
 }
 
 result = LSEEK(_M_file_id, offset, whence);
 
 returnresult;
}
 
 
 
// Helper functiosn for seek and imbue
 
template <class _CharT, class _Traits>
typenamebasic_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;
}
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章