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;
public: basic_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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.