std::ios 等学习笔记
std::ios_base
ios_base
类是一个多用途类,用作所有 I/O 流类的基类。它维护着几种数据:
- 状态信息:流状态标志
- 控制信息:控制输入和输出序列的格式以及语言环境的标志
- 私有存储:可扩展索引数据结构,允许
long
和void*
成员,它可以实现为两个任意长度的数组或两个元素结构的单个数组或另一个容器 - 回调函数:从
imbue()
、std::basic_ios::copyfmt()
和~ios_base()
调用的任意数量的用户定义函数
成员变量
openmode
流打开的模式类型,包括以下常量值
app
: 在每次写入之前移到流的末尾(追加模式)binary
: 以二进制方式打开in
: 以读取的方式打开out
: 以写入的方式打开trunc
: 打开时丢弃流的内容ate
: 打开后立即移到流的末尾
MSVC 中定义如下:
enum _Openmode { // constants for file opening options |
fmtflags
格式化标志
dec
: 整数 I/O 使用十进制基数oct
: 整数 I/O 使用八进制基数hex
: 整数 I/O 使用十六进制基数basefield
:dec|oct|hex
, 对屏蔽操作很有用left
: 左对齐(向右添加填充字符)right
: 右对齐(向左添加填充字符)internal
: 内部调整(将填充字符添加到内部指定点)adjustfield
:left|right|internal
, 对屏蔽操作很有用scientific
: 使用科学记数法或十六进制记数法(如果与fixed
结合)生成浮点类型fixed
: 使用固定表示法或十六进制表示法(如果与scientific
结合)生成浮点类型floatfield
:scientific|fixed
, 对屏蔽操作很有用boolalpha
: 以字母数字格式插入和提取布尔类型showbase
: 生成指示整数输出的数字基数的前缀showpoint
: 为浮点数输出无条件生成小数点字符showpos
: 为非负数输出生成+
字符skipws
: 在某些输入操作之前跳过前导空格unitbuf
: 每次输出操作后刷新输出uppercase
: 在某些输出操作中的等价条件下,用大写字母替换某些小写字母
MSVC 中定义如下:
enum _Fmtflags { // constants for formatting options |
iostate
流的状态
goodbit
: 没有错误badbit
: 不可恢复的流错误failbit
: 输入/输出操作失败(格式化或提取错误)eofbit
: 关联的输入序列已到达文件结尾
MSVC 中定义如下:
enum _Iostate { // constants for stream states |
seekdir
流指针位置
beg
: 流开始位置end
: 流末尾位置cur
: 流当前的位置
MSVC 中定义如下:
enum _Seekdir { // constants for file positioning options |
event
事件。指定传递给 register_callback()
在特定事件上注册的函数的事件类型。
erase_event
imbue_event
copyfmt_event
event_callback
事件函数回调
typedef void (*event_callback)(event type, ios_base& ios, int index); |
成员函数
flags
fmtflags flags() const; // 获取当前设置的格式 |
setf
fmtflags setf(fmtflags flags); // 设置当前格式,fl = fl | flags |
unsetf
void unsetf(fmtflags flags); // 取消设置由标志标识的格式化标志 |
precision
using streamsize = long long; |
width
streamsize width() const; // 获取当前设置的宽度 |
imbue
std::locale imbue(const std::locale& loc); // 设置语言环境,返回前一次设置的语言环境 |
getloc
std::locale getloc() const; // 获取当前的语言环境 |
xalloc & iword & pword
static int xalloc(); // 返回一个范围内的唯一整数,可以安全地用作 pword() 和 iword() 的索引 |
register_callback
注册回调函数,回调函数可能会被 imbue()
, std::basic_ios::copyfmt()
和 ~ios_base()
调用。
回调以注册的相反顺序调用。如果从回调函数中调用 register_callback() 以添加新回调,则仅在下一个事件时调用新回调。
用户自定义回调函数不允许抛出异常。
typedef void (*event_callback)(event type, ios_base& ios, int index); |
sync_with_stdio
设置标准 C++ 流是否在每次输入/输出操作后与标准 C 流同步。
标准 c++ 流包括:std::cin
, std::cout
, std::cerr
, std::clog
, std::wcin
, std::wcout
, std::wcerr
, std::wclog
标准 C 流包括:stdcin
, stdcout
, stderr
‘
对于一个标准流 str,与 C 流 f 同步,则以下情况是等效的:
std::fputc(f, c)
&str.rdbuf()->sputc(c)
std::fgetc(f)
&str.rdbuf()->sbumpc()
std::ungetc(c, f)
&str.rdbuf()->sputbackc(c)
实际上,这意味着同步的 C++ 流是无缓冲的,并且 C++ 流上的每个 I/O 操作都会立即应用于相应的 C 流的缓冲区。这使得自由混合 C++ 和 C I/O 成为可能。
此外,同步的 C++ 流保证是线程安全的。如果关闭同步,则允许 C++ 标准流独立缓冲其 I/O,这在某些情况下可能会快得多。
failure 类
failure 类定义了输入输出库在调用函数失败时抛出的异常。从 c++ 11 之后,failure 的继承关系如下:
exception <- runtime_error <- system_errro <- ios_base::failure |
explicit failure(const std::string& message); |
std::basic_ios
std::basic_ios
定义在 <ios>
头文件中,其声明如下:
template<class CharT, class Traits = std::char_traits<CharT>> |
对于 char 和 wchar_t,有对应的偏特化模板
using ios = basic_ios<char, char_traits<char>>; |
成员函数
constructor & destructor
explicit basic_ios(std::basic_streambuf<CharT,Traits>* sb); |
State functions
iostate rdstate() const; // 返回当前流错误状态 |
copyfmt
如果 other
和 *this
是同一个对象,则不会有效果。否则,拷贝 other
对象中的状态到 *this
中。
basic_ios& copyfmt(const basic_ios& other); |
fill
fill 管理用于将输出转换填充到指定字段宽度的填充字符
CharT fill() const; // 获取当前设置的填充字符 |
exceptions
exceptions 管理异常掩码标志,异常掩码确定哪些错误状态会触发失败类型的异常。如果流在调用时具有被异常掩码覆盖的错误状态,则会立即触发异常。
std::ios_base::iostate exceptions() const; // 获取异常掩码 |
imbue
imbue 设置语言环境
std::locale imbue(const std::locale& loc); // 设置语言环境,并返回上次的语言环境 |
rdbuf
管理相关的流缓冲区。
相关函数可能会抛异常
这里 rd
前缀表示 read,参考 What does STL “rdbuf” method name stand for?
// 返回关联的流缓冲区,如果没有关联的流缓冲区,则返回一个空指针 |
tie
管理绑定的流。绑定流是与流缓冲区 (rdbuf()
) 控制的序列同步的输出流,也就是说,在对 *this
进行任何输入/输出操作之前,在绑定流上调用 flush()
。
相关函数可能抛异常
// 返回当前绑定的流。如果没有绑定流,则返回空指针 |
narrow
将当前特定于语言环境的字符 c 转换为其标准等效字符。如果需要,结果会从 char_type 转换为 char。如果无法执行转换,则该函数返回 dfault。
等效于调用 std::use_facet<std::ctype<char_type>>(getloc()).narrow(c, dfault);
char narrow(char_type c, char dfault) const; |
widen
将字符 c 转换为当前语言环境中的等效字符。如果需要,结果会从 char 转换为流中使用的字符类型。
等效于调用 std::use_facet<std::ctype<char_type>>(getloc()).widen(c)
char_type widen(char c) const; |
init
将关联的流缓冲区设置为 sb 并初始化内部状态。此成员函数是受保护的:一旦相关的流缓冲区已知,它就由派生流类 std::basic_istream
和 std::basic_ostream
的构造函数调用。
protected: |
初始化后状态如下:
Element | Value | |
---|---|---|
rdbuf() |
sb | |
tie() |
null pointer | |
rdstate() |
goodbit if sb is not a null pointer, otherwise badbit |
|
exceptions() |
goodbit |
|
flags() |
`skipws | dec` |
width() |
0 | |
precision() |
6 | |
fill() |
widen(' ') |
|
getloc() |
a copy of the value returned by std::locale() |
move
将当前状态(rdbuf 除外)替换为其他状态。other
在调用后处于有效但未指定的状态。调用此函数后,rdbuf()
返回空指针,other.rdbuf()
返回与调用前相同的值,other.tie()
返回空指针。
protected: |
swap
交换 *this 和 other 的状态(rdbuf 除外)。rdbuf()
和 other.rdbuf()
返回与调用前相同。
protected: |
set_rdbuf
将关联的流缓冲区设置为 sb 而不清除错误状态。
protected: |
std::basic_streambuf
template< |
std::basic_streambuf
定义在 <streambuf>
头文件中
类 basic_streambuf 控制字符序列的输入和输出。其包括:
- 受控字符序列,也称为缓冲区。缓冲区中包含用于缓冲输入操作的输入序列(也称为
get area
)和/或用于缓冲输出操作的输出序列(也称为put area
) - 关联的字符序列,也称为 source(用于输入)或 sink(用于输出)。这可能是通过 OS API 访问的实体(文件、TCP 套接字、串行端口、其他字符设备),也可能是可以解释为字符 source 或 sink 的对象(
std::vector
、数组、字符串字面量)
I/O 流对象(std::basic_istream
, std::basic_ostream
及其继承的对象)都是根据 std::basic_streambuf
来实现的。
受控字符序列是一个 CharT 数组,它始终表示一个子序列,或关联字符序列的“窗口”。它的状态由三个指针描述:
- 开始指针(下文用
begin
代替),总是指向缓冲区的最低元素 - 下一个指针(下文用
next
代替),指向下一个读取或写入候选的元素 - 结束指针(下文用
end
代替),指向缓冲区末尾的下一个位置
basic_streambuf
对象可以支持输入、输出或同时输入输出。
- 在作为输入时,3 个指针构成 get area
- 在最为输出时,3 个指针构成 put area
- 在输入输出时,会追踪 6 个指针,它们可能都指向同一个字符数组或指向两个单独的数组
在 put area 中,当 next
指针小于 end
指针时认为写位置(write position)可用。next
指针可以解引用和赋值
在 get area 中,当 next
指针小于 end
指针时认为读位置(read position)可用。next
指针可以解引用和赋值
在 get area 中,当 next
指针大于 begin
指针时认为回退位置(putback position)可用。next
指针可以递减、解引用和赋值。能够将字符放回去
受控序列中的字符表示和编码可能与关联序列中的字符表示不同,这种情况下,通常使用 std::codecvt
locale facet 来执行转换。
std::basic_streambuf
基类的典型实现仅包含六个 CharT*
指针和 std::locale
的副本作为数据成员。此外,实现可以保留 locale facet 的缓存副本,只要 imbue()
被调用,这些副本就会失效。std::basic_filebuf
或 std::basic_stringbuf
之类的具体缓冲区是从 std::basic_streambuf
派生的。
两种常见的偏特化:
using stringbuf = basic_stringbuf<char, char_traits<char>, allocator<char>>; |
Locales
imbue
虚函数,由派生类实现。设置关联的 locale 为 loc
。
protected: |
pubimbue
设置关联的 locale 为 loc
,调用派生类的 imbue
实现。返回上次设置的 locale
std::locale pubimbue(const std::locale& loc); |
getloc
获取关联的 locale。关联的 locale 是通过最后一次调用 pubimbue
设置的。如果未调用过 pubimbue
,则返回构造时的全局 locale
std::locale getloc() const; |
Positioning
setbuf & seekoff & seekpos & sync
setbuf
, seekoff
, seekpos
和 sync
为虚函数,需要派生类实现自己的功能。
protected: |
pubsetbuf & pubsetseekoff & pubseekpos & pubsync
pubsetbuf
, pubseekoff
, pubseekpos
和 pubsync
通过调用派生类实现的上面介绍的对象接口来实现。其功能和对应虚函数相同。
public: |
Get area
这部分函数是针对输入流缓冲区的操作
showmanyc [virtual]
虚函数,由派生类实现。估计关联字符序列中可用于输入的字符数。
The name of this function stands for “stream: how many characters?”, so it is pronounced “S how many C”, rather than “show many C”.
protected: |
underflow [virtual]
虚函数,需要由派生类实现。通过更新指向输入区的指针(如果需要)并从输入序列中读取更多数据(如果适用),确保输入区中至少有一个字符可用。返回可用字符的数量
protected: |
uflow [virtual]
虚函数,需要由派生类实现。通过更新指向输入区的指针(如果需要)确保输入区中至少有一个字符可用。成功时返回该字符的值并将 get 指针的值前移一个字符。
protected: |
xsgetn
虚函数,需要由派生类实现。从输入序列中读取指定数量的字符到 s 中。返回实际读取到的字符数量
protected: |
eback & gptr & egptr
获取输入区相关指针
While the names “gptr” and “egptr” refer to the get area, the name “eback” refers to the end of the putback area: stepping backwards from gptr, characters can be put back until eback.
char_type* eback() const; // 指向输入区 begin 的指针 |
gbump
从输入区中跳过 count 个字符
protected: |
setg
设置输入缓冲区的指针
protected: |
std::basic_istream
template< |
std::basic_istream
是类模板,提供字符流的高级输入。支持的操作包括格式化输入(例如整数值或空格分隔的字符和字符串)和未格式化输入(例如原始字符和字符数组)
该类模板中函数是根据底层 basic_streambuf
类提供的接口实现的,通过 basic_ios
基类访问。
在大多数实现中,basic_istream 的唯一非继承数据成员是 basic_istream::gcount() 返回的值。
该模板定义了两种常见的偏特化:
using istream = basic_istream<char, char_traits<char>>; |
constructor
explicit basic_istream(std::basic_streambuf<CharT, Traits>* sb); |
operator=
protected: |
operator>>
控制输入流的格式,提取对应类型的值
basic_istream& operator>>(short& value); |
get
从流中提取一个或多个字符。
int_type get(); // 读取一个字符并在可用时返回 |
peek
在构造和测试 sentry object后,从输入流中读取下一个字符而不提取。可能会抛异常
int_type peek(); |
unget
使最近提取的字符再次可用。可能会抛异常
basic_istream& unget(); |
putback
将字符 ch 放回输入流,以便下一个提取的字符是 ch。可能会抛异常
basic_istream& putback(char_type ch); |
getline
从流中提取字符直到行尾或指定的分隔符 delim。可能会抛异常
basic_istream& getline(char_type* s, std::streamsize count); // 默认 delim 为 \n |
ignore
从输入流中提取和丢弃字符,直到并包括 delim。可能会抛异常
basic_istream& ignore(std::streamsize count = 1, int_type delim = Traits::eof()); |
read
从流中提取字符。可能会抛异常
basic_istream& read(char_type* s, std::streamsize count); |
readsome
从输入流中提取最多 count 个立即可用的字符。提取的字符存储到 s 指向的字符数组中。可能会抛异常
std::streamsize readsome(char_type* s, std::streamsize count); |
gcount
返回由最后一个无格式输入操作提取的字符数,如果该数字不可表示,则返回 std::streamsize 的最大可表示值。
std::streamsize gcount() const; |
tellg
返回当前关联的 streambuf 对象的输入位置指示符。可能会抛异常
这里 g 可以看做是 get position
pos_type tellg(); |
seekg
设置当前关联的 streambuf 对象的输入位置指示器。可能会抛异常
这里 g 可以看做是 get position
basic_istream& seekg(pos_type pos); // 绝对位置 |
sync
将输入缓冲区与关联的数据源同步。
int sync(); |
swap
protected: |
std::basic_ostream
template< |
类模板 basic_ostream
为字符流的高级输出操作提供支持。支持的操作包括格式化输出(例如整数值)和未格式化输出(例如原始字符和字符数组)
该类模板中的函数是根据 basic_streambuf
类提供的接口实现的,通过 basic_ios
基类访问。在典型的实现中,basic_ostream
没有非继承的数据成员。
有以下两个常用类型的偏特化:
using ostream = basic_ostream<char, char_traits<char>>; |
constructor
explicit basic_ostream(std::basic_streambuf<CharT, Traits>* sb); |
operator=
protected: |
operator<<
插入数据到流中
basic_ostream& operator<<(short value); |
put
插入一个字符到流中
basic_ostream& put(char_type ch); |
write
插入字符串到流中,最多插入 count 个字符,可能会抛异常。
basic_ostream& write(const char_type* s, std::streamsize count); |
tellp
返回当前关联的 streambuf
对象的输出位置指示符。不会抛异常,失败返回 -1
。
这里 p 可以看做是 put position
pos_type tellp(); |
seekp
设置当前关联的 streambuf
对象的输出位置指示器。可能会抛异常。
basic_ostream& seekp(pos_type pos); // 绝对位置 |
flush
将未提交的更改写入基础输出序列。如果 rdbuf() 是空指针,则不执行任何操作。可能会抛异常。
basic_ostream& flush(); |
swap
protected: |
std::basic_iostream
template< |
两个常见类型的偏特化:
using iostream = basic_iostream<char, char_traits<char>>; |
constructor
explicit basic_iostream(std::basic_streambuf<CharT,Traits>* sb); |
operator=
basic_iostream& operator=(const basic_iostream& other) = delete; |
swap
protected: |
std::basic_stringbuf
template< |
std::basic_istringstream
template< |
std::basic_istringstream
继承与 std::basic_istream
类模板 std::basic_istringstream
在基于字符串的流上实现输入操作。它有效地存储 std::basic_string 的实例并对其执行输入操作。
底层实现是调用的 std::basic_stringbuf
的接口。
对于常用类型的偏特化:
using istringstream = basic_istringstream<char, char_traits<char>, allocator<char>>; |
constructor
// 默认构造函数,使用默认打开方式构造 |