摘自: http://blog.csdn.net/linweixuan/archive/2006/09/09/1197236.aspx
文件流要使用的
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;
}