template <class charT, class traits = char_traits<charT> > class basic_istream;
输入流:包装给定的抽象设备(std::basic_streambuf)并提供高层输入接口
输入流对象可以读取和解释字符序列中的输入。提供了特定的成员来执行这些输入操作(参见下面的函数)。
模板实例化
它对常用字符类型定义了二个具体类:
类型 定义 basic_istream<char> basic_istream<wchar_t> 这些实例化在<istream>中声明,它通过引用包含在<iostream>中。
标准库于头文件
<iostream>
中提供二个全局 basic_istream 对象extern std::istream cin; extern std::wistream wcin;
成员类型
成员类型 描述 note char_type 第一个模板参数(charT) traits_type 第二个模板参数(traits) 默认char_traits<charT> int_type traits_type::int_type pos_type traits_type::pos_type 一般来说,与 streampos相同 off_type traits_type::off_type 一般来说,与 streamoff相同 以及从ios_base继承的成员类型 :
表示事件类型的类型(公共成员类型) 事件回调函数类型(公共成员类型) 流异常的基类(公共成员类) 流格式标志的类型(公共成员类型) 初始化标准流对象(公共成员类) 流状态标志的类型(公共成员类型) 流打开模式标志的类型(公共成员类型) 流搜索方向标志的类型(公共成员类型) --
公共成员函数
构造对象 (公开成员函数) | |
(析构函数) [虚] | 析构对象 (虚公开成员函数) |
operator= (C++11) | 从另一 basic_istream 移动赋值 (受保护成员函数) |
std::basic_istream::basic_istream
explicit basic_istream( std::basic_streambuf<CharT, Traits>* sb); (1) protected: basic_istream( const basic_istream& rhs ) = delete; (2) (C++11 起) protected: basic_istream( basic_istream&& rhs ); (3) (C++11 起)
- 1) 构造
basic_istream
对象,通过调用 basic_ios::init(sb) 赋初始值给基类。初始化gcount()
的值为零。- 2) 复制构造函数为受保护,且被删除。输入流不可复制。
- 3) 移动构造函数从
rhs
复制gcount()
的值,设置 rhs 的 gcount() 值为零,并使用basic_ios<CharT, Traits>::move(rhs)
从rhs
移动所有 basic_ios 成员,除了rdbuf()
到*this
中。此移动构造函数受保护:它为可移动输入流类 std::basic_ifstream 和 std::basic_istringstream 的移动构造函数调用,它们知道如何正确地移动关联流缓冲。
#include <sstream>
#include <iostream>
int main()
{
std::istringstream s1("hello");
std::istream s2(s1.rdbuf()); // OK : s2 与 s1 共享缓冲
// std::istream s3(std::istringstream("test")); // 错误:移动构造函数为受保护
// std::istream s4(s2); // 错误:复制构造函数被删除
std::istringstream s5(std::istringstream("world")); // OK :导出类调用移动构造函数
std::cout << s2.rdbuf() << ' ' << s5.rdbuf() << '\n';
}
std::basic_istream::〜basic_istream
virtual ~basic_istream();
析构输入流。
- 此析构函数不在底层流缓冲(
rdbuf()
)上进行任何操作:导出输入流,如 std::basic_ifstream 和 std::basic_istringstream 的析构函数负责调用流缓冲的析构函数。
#include <sstream>
#include <iostream>
void print_stringbuf(std::streambuf* p)
{
std::istream buf(p); // buf 与 s1 共享缓冲
int n;
buf >> n;
std::cout << n;
} // 调用 buf 的析构函数。 p 保持不受影响
int main()
{
std::istringstream s1("10 20");
print_stringbuf(s1.rdbuf());
int n;
s1 >> n;
std::cout << ',' << n << '\n';
}
std::basic_istream::operator=
protected:
basic_istream& operator=( const basic_istream& rhs ) = delete;(1) protected:
basic_istream& operator=( basic_istream&& rhs );(2) (C++11 起) 1) 复制赋值运算符受保护且被删除。输入流不可复制赋值 (CopyAssignable) 。
2) 移动赋值运算符和
rhs
交换 the gcount() 值和所有基类的数据成员,除了rdbuf()
,如同以调用 swap(*rhs) 。此移动赋值运算符为受保护:它只为导出的可移动输入流类 std::basic_ifstream 和 std::basic_istringstream 的移动赋值运算符调用,它们知道如何正确地移动赋值关联的流缓冲。--
#include <sstream>
#include <iostream>
int main()
{
std::istringstream s1;
s1 = std::istringstream("test"); // OK
std::cin = std::istringstream("test"); // 错误: 'operator=' 为受保护
}
operator>> | 提取带格式的字符 |
std::basic_istream::operator >>
basic_istream& operator>>( short& value );
basic_istream& operator>>( unsigned short& value );(1) basic_istream& operator>>( int& value );
basic_istream& operator>>( unsigned int& value );(2) basic_istream& operator>>( long& value );
basic_istream& operator>>( unsigned long& value );(3) basic_istream& operator>>( long long& value );
basic_istream& operator>>( unsigned long long& value );(4) (C++11 起) basic_istream& operator>>( float& value ); basic_istream& operator>>( double& value );
basic_istream& operator>>( long double& value );(5) basic_istream& operator>>( bool& value );
(6) basic_istream& operator>>( void*& value );
(7) basic_istream& operator>>( std::ios_base& (*func)(std::ios_base&) );
(8) basic_istream& operator>>( std::basic_ios<CharT,Traits>&
(*func)(std::basic_ios<CharT,Traits>&) );(9) basic_istream& operator>>( basic_istream& (*func)(basic_istream&) );
(10) basic_istream& operator>>( std::basic_streambuf<CharT,Traits>* sb );
(11)
#include <iostream>
#include <iomanip>
#include <sstream>
int main()
{
std::string input = "41 3.14 false hello world";
std::istringstream stream(input);
int n;
double f;
bool b;
stream >> n >> f >> std::boolalpha >> b;
std::cout << "n = " << n << '\n'
<< "f = " << f << '\n'
<< "b = " << std::boolalpha << b << '\n';
// 用 streambuf 重载释出剩余内容
stream >> std::cout.rdbuf();
std::cout << '\n';
}
get | 从流中读并取走(移除类似指针向下一个元素移动)一个字符 |
peek | 仅读出但不取走(不移除类似指针并未移动)一个字符 |
unget | 撤销流中刚取走(移除,类似指针向后退回一个位置)的字符 |
putback | 往输入流中退回一个字符 |
getline | 一直读并取走字符,直至找到给定字符 |
ignore | 读且取走并舍弃字符,直至发现给定字符 |
read | 读并取走一块字符 |
readsome | 读并取走已经可用的字符块 |
gcount | 返回上次无格式输出操作所取走的字符数量 |
std::basic_istream::get
int_type get();
(1) basic_istream& get( char_type& ch );
(2) basic_istream& get( char_type* s, std::streamsize count );
(3) basic_istream& get( char_type* s, std::streamsize count, char_type delim );
(4) basic_istream& get( basic_streambuf& strbuf );
(5) basic_istream& get( basic_streambuf& strbuf, char_type delim );
(6) 参数
ch - 到要写入结果到的字符的引用 s - 指向要存储结果到的字符串的指针 count - s
所指向的字符串的大小delim - 用以停止释出的分隔字符。不释出且不存储它。 strbuf - 要读取内容到的流缓冲 返回值
1) 释出的字符或 Traits::eof()
2-6) *this
异常
若出现错误(错误状态标志不是 goodbit )并且设置了 exceptions() 为对该状态抛出则为 failure 。若内部操作抛出异常,则捕获它并设置 badbit 。若对
badbit
设置了 exceptions() ,则重抛该异常。
#include <sstream>
#include <iostream>
int main()
{
std::istringstream s1("Hello, world.");
char c1 = s1.get(); // 读取'H'
std::cout << "after reading " << c1 << ", gcount() == " << s1.gcount() << '\n';
char c2;
s1.get(c2); // 读取 'e'
char str[5];
s1.get(str, 5); // 读取 "llo,"
std::cout << "after reading " << str << ", gcount() == " << s1.gcount() << '\n';
std::cout << c1 << c2 << str;
s1.get(*std::cout.rdbuf()); // 读取剩余,不包括 '\n'
std::cout << "\nAfter the last get(), gcount() == " << s1.gcount() << '\n';
}
std::basic_istream::peek
int_type peek();
表现为无格式输入函数 (UnformattedInputFunction) 。构造并测试 sentry 对象后,从输入流读取下个字符而不释出它。
参数
(无)
返回值
若 good() == true ,则返回获得自 rdbuf()->sgetc() 的下个字符。
否则,返回 Traits::eof() 。
异常
若出现错误(错误状态标志不是 goodbit )并且设置了 exceptions() 为对该状态抛出则为 failure 。若内部操作抛出异常,则捕获它并设置 badbit 。若对
badbit
设置了 exceptions() ,则重抛该异常。
#include <sstream>
#include <iostream>
int main()
{
std::istringstream s1("Hello, world.");
char c1 = s1.peek();
char c2 = s1.get();
std::cout << "Peeked: " << c1 << " got: " << c2 << '\n';
}
std::basic_istream::unget
basic_istream& unget();
令最近释出的字符再次可用。
- 首先清除 eofbit ((C++11 起))。
- 然后函数表现为无格式输入函数 (UnformattedInputFunction) 。构造并检查 sentry 对象后,若设置了任何 ios_base::iostate 标志,则函数设置
failbit
并返回。否则,调用 rdbuf()->sungetc() 。- 若 rdbuf()->sungetc() 返回 Traits::eof() ,则调用 setstate(badbit) 。
- 任何情况下,设置
gcount()
计数器为零。参数
(无)
返回值
*this
异常
若出现错误(错误状态标志不是 goodbit )并且设置了 exceptions() 为对该状态抛出则为 failure 。若内部操作抛出异常,则捕获它并设置 badbit 。若对
badbit
设置了 exceptions() ,则重抛该异常。
#include <sstream>
#include <iostream>
int main()
{
std::istringstream s1("Hello, world.");
char c1 = s1.get();
if (s1.unget())
{
char c2 = s1.get();
std::cout << "Got: " << c1 << " got again: " << c2 << '\n';
}
}
std::basic_istream::putback
basic_istream& putback( char_type ch );
作用:往输入流中退回一个字符
- 回放字符
ch
到输入流,从使得下个释出的字符将为ch
。- 首先清除
eofbit
,然后表现为无格式输入函数 (UnformattedInputFunction) 。构造并检查 sentry 对象后,若rdbuf()
非空,则调用 rdbuf()->sputbackc(ch) ,若ch
不等于最近输出的字符,则它调用 rdbuf()->pbackfail(ch) 。- 若
rdbuf()
为空或若 rdbuf->sputbackc(ch) 返回 Traits::eof() ,则调用 setstate(badbit) 。- 任何情况下,设置
gcount()
计数器为零。--
// modify flags
#include <iostream> // std::cout, std::ios
#include <sstream>
int main () {
std::stringstream s1("Hello, world"); // IO 流
s1.get();
if (s1.putback('Y')) // 修改缓冲区
std::cout << s1.rdbuf() << '\n';
else
std::cout << "putback failed\n";
std::istringstream s2("Hello, world"); // 仅输入流
s2.get();
if (s2.putback('Y')) // cannot modify input-only buffer
std::cout << s2.rdbuf() << '\n';
else
std::cout << "putback failed\n";
s2.clear();
if (s2.putback('H')) // 非修改回放
std::cout << s2.rdbuf() << '\n';
else
std::cout << "putback failed\n";
return 0;
}
std::basic_istream::getline
basic_istream& getline( char_type* s, std::streamsize count );
(1) basic_istream& getline( char_type* s, std::streamsize count, char_type delim );
(2) 从流释出字符,直至行尾或指定的分隔符
delim
。第一版本等价于 getline(s, count, widen('\n')) 。
表现为无格式输入函数 (UnformattedInputFunction) 。构造并检查 sentry 对象后,从
*this
释出字符并存储它们于首元素为s
所指向的数组的相继位置,直至出现任何下列条件(按出示顺序测试):
- 输入序列中出现文件尾条件(该情况下执行 setstate(eofbit) )
- 下个可用字符
c
是以 Traits::eq(c, delim) 确定的分隔符。释出该分隔符(不同于 basic_istream::get() )并计入gcount()
,但不存储它。
- 已经释出 count-1 个字符(该情况下执行 setstate(failbit) )。
若函数未释出字符(即 count < 1 ),则执行 setstate(failbit) 。
任何情况下,若
count>0
,则它存储空字符CharT()
到数组的下个相继位置,并更新gcount()
。注意
因为条件 #2 在条件 #3 前测试,故准确适合缓冲区的输入行不会触发 failbit 。
因为终止字符计为释出的字符,故空输入行不触发 failbit 。
参数
s - 指向要存储字符到的字符串的指针 count - s
所指向的字符串的大小delim - 释出所终止于的分隔字符。释出但不存储它。 返回值
*this
异常
若出现错误(错误状态标志不是 goodbit )并且设置了 exceptions() 为对该状态抛出则为 failure 。若内部操作抛出异常,则捕获它并设置 badbit 。若对
badbit
设置了 exceptions() ,则重抛该异常。
#include <iostream>
#include <sstream>
#include <vector>
#include <array>
int main () {
std::istringstream input("abc|def|gh");
std::vector<std::array<char, 4>> v;
// 注意:下列循环在从 getline() 返回的流上的
// std::ios_base::operator bool() 返回 false 时终止
for (std::array<char, 4> a; input.getline(&a[0], 4, '|'); ) {
v.push_back(a);
}
for (auto& a : v) {
std::cout << &a[0] << '\n';
}
return 0;
}
std::basic_istream::ignore
basic_istream& ignore( std::streamsize count = 1, int_type delim = Traits::eof() );
从输入流释出并舍弃字符,直至并包含
delim
。
ignore
表现为无格式输入函数 (UnformattedInputFunction) 。构造并检查 sentry 对象后,它从流释出并舍弃字符,直至出现任一下列条件:
- 已释出
count
个字符。在count
等于 std::numeric_limits<std::streamsize>::max() 的特殊情况下禁用此测试。
- 输入序列中出现文件尾条件,该情况下函数调用 setstate(eofbit) 。
- 输入序列中下个可用字符
c
为delim
,以 Traits::eq_int_type(Traits::to_int_type(c), delim) 确定。释出并舍弃分隔符。若 Traits::eof() 为则禁用此测试。参数
count - 要释出的字符数 delim - 释出所止于的分隔字符。亦释出之。 返回值
*this
异常
若出现错误(错误状态标志不是 goodbit )并且设置了 exceptions() 为对该状态抛出则为 failure 。若内部操作抛出异常,则捕获它并设置 badbit 。若对
badbit
设置了 exceptions() ,则重抛该异常。
#include <iostream>
#include <sstream>
#include <limits>
int main()
{
std::istringstream input("1\n"
"some non-numeric input\n"
"2\n");
for(;;) {
int n;
input >> n;
if (input.eof() || input.bad()) {
break;
} else if (input.fail()) {
input.clear(); // 反设置 failbit
input.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // 跳过坏输入
} else {
std::cout << n << '\n';
}
}
}
std::basic_istream::read
basic_istream& read( char_type* s, std::streamsize count );
从流释出字符。
表现为无格式输入函数 (UnformattedInputFunction) 。构造并检查 sentry 对象后,释出字符并存储它们到首元素为
s
所指向的字符数组的相继位置。释出并存储字符,直至出现任何下列条件:
- 释出并存储了
count
个字符
- 输入序列上的文件尾条件(该情况下调用 setstate(failbit|eofbit) )。成功释出的字符数能用 gcount() 查询。
参数
s - 指向要存储字符到的字符数组的指针 count - 要读取的字符数 返回值
*this
异常
若出现错误(错误状态标志不是 goodbit )并且设置了 exceptions() 为对该状态抛出则为 failure 。若内部操作抛出异常,则捕获它并设置 badbit 。若对
badbit
设置了 exceptions() ,则重抛该异常。注意
使用非转换的本地环境时(默认本地环境为非转换),此函数在 std::basic_ifstream 中的覆写者可以为零复制的大块 I/O 优化(通过覆写 std::streambuf::xsgetn )。
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstdint>
int main()
{
// read() 常用于二进制 I/O
std::string bin = {'\x12', '\x12', '\x12', '\x12'};
std::istringstream raw(bin);
std::uint32_t n;
if(raw.read(reinterpret_cast<char*>(&n), sizeof n))
std::cout << std::hex << std::showbase << n << '\n';
// 为下个片段准备文件
std::ofstream("test.txt", std::ios::binary) << "abcd1\nabcd2\nabcd3";
// 读取整个文件到 string
if(std::ifstream is{"test.txt", std::ios::binary | std::ios::ate}) {
auto size = is.tellg();
std::string str(size, '\0'); // 构造 string 为流大小
is.seekg(0);
if(is.read(&str[0], size))
std::cout << str << '\n';
}
}
std::basic_istream::readsome
std::streamsize readsome( char_type* s, std::streamsize count );
从输入流释出至多
count
个立即可用的字符。存储释出的字符于s
所指向的字符数组。表现为无格式输入函数 (UnformattedInputFunction) 。构造并检查 sentry 对象后,
- 若 rdbuf()->in_avail() == -1 ,则调用 setstate(eofbit) 而不释出字符。
- 若 rdbuf()->in_avail() == 0 ,则不释出字符。
- 若 rdbuf()->in_avail() > 0 ,则释出 std::min(rdbuf()->in_avail(), count) 个字符,并存储它们到首元素为
s
所指向的字符数组的相继位置。参数
s - 指向要存储字符到的字符数组的指针 count - 要读取的最大字符数 返回值
实际释出的字符数。
异常
若出现错误(错误状态标志不是 goodbit )并且设置了 exceptions() 为对该状态抛出则为 failure 。若内部操作抛出异常,则捕获它并设置 badbit 。若对
badbit
设置了 exceptions() ,则重抛该异常。注意
此函数的行为是高度实现限定的。例如,以 std::ifstream 使用时,某些库实现在文件打开时立即以数据填充底层 filebuf (而这种实现上 readsome() 读取的数据潜在地,但不必为整个文件),而其他实现仅在请求实际输入操作时从文件读取(而文件打开后立即作出的 readsome() 决不释出任何字符)。类似地,调用 std::cin.readsome() 可能返回所有悬置的未处理控制台输入,或可能始终返回零并且不释出字符。
#include <iostream>
#include <sstream>
int main()
{
char c[10] = {};
std::istringstream input("This is sample text."); // std::stringbuf 令个缓冲可用于无阻塞读取
input.readsome(c, 5); // 读取 'This ' 并存储于 c[0] .. c[4]
input.readsome(c, 9); // 读取 'is sample' 并存储于 c[0] .. c[8]
std::cout << c;
}
std::basic_istream::gcount
std::streamsize gcount() const;
返回最近的无格式输入操作所提取的字符数,或若该数不可表示则返回 std::streamsize 的最大可表示值。
basic_istream
的下列成员函数更改后继的gcount()
调用的值:下列函数设置
gcount()
为零:参数
(无)
返回值
最近的无格式输入操作所提取的字符数,或若该数不可表示则返回 std::streamsize 的最大可表示值。
#include <iostream>
#include <sstream>
int main()
{
char x[20];
std::istringstream stream("Hello World");
stream.read(x, sizeof x);
std::cout << "Characters extracted: " << stream.gcount();
}
tellg | 返回输入位置指示器 |
seekg | 设置输入位置指示器 |
std::basic_istream::tellg
pos_type tellg();
返回当前关联的
streambuf
对象的输入位置指示器。表现为无格式输入函数 (UnformattedInputFunction) ,除了不影响 gcount() 。构造并检查 sentry 对象后,若 fail() == true ,则返回 pos_type(-1) 。否则,返回 rdbuf()->pubseekoff(0, std::ios_base::cur, std::ios_base::in) 。
参数
(无)
返回值
成功时为获取指针的当前位置,失败时为 pos_type(-1) 。
异常
若出现错误(错误状态标志不是 goodbit )并且设置了 exceptions() 为对该状态抛出则为 failure 。若内部操作抛出异常,则捕获它并设置 badbit 。若对
badbit
设置了 exceptions() ,则重抛该异常。
#include <iostream>
#include <string>
#include <sstream>
int main()
{
std::string str = "Hello, world";
std::istringstream in(str);
std::string word;
in >> word;
std::cout << "After reading the word \"" << word
<< "\" tellg() returns " << in.tellg() << '\n';
}
std::basic_istream::seekg
basic_istream& seekg( pos_type pos ); basic_istream& seekg( off_type off, std::ios_base::seekdir dir);
设置当前关联
streambuf
对象的输入位置指示器,失败的情况下调用 setstate(std::ios_base::failbit) 。> 从C++11起,进行任何其他动作前,
seekg
清除eofbit
。
seekg
表现为无格式输入函数 (UnformattedInputFunction) ,除了不影响 gcount() 。构造并检查 sentry 对象后,1) 设置输入位置指示器为绝对(相对于文件起始)值
pos
。具体而言,执行 rdbuf()->pubseekpos(pos, std::ios_base::in) 。2) 设置输入位置指示器为相对于
dir
所定义位置的off
。具体而言,执行 rdbuf()->pubseekoff(off, dir, std::ios_base::in) 。参数
pos 设置输入位置指示器到的绝对位置。 off 设置输入位置指示器到的相对位置。 dir 定义应用相对偏移到的基位置。它能为下列常量之一:
常量 解释 beg 流的开始 end 流的结尾 cur 流位置指示器的当前位置 返回值
*this
异常
若出现错误(错误状态标志不是 goodbit )并且设置了 exceptions() 为对该状态抛出则为 failure 。若内部操作抛出异常,则捕获它并设置 badbit 。若对
badbit
设置了 exceptions() ,则重抛该异常
#include <iostream>
#include <string>
#include <sstream>
int main()
{
std::string str = "Hello, world";
std::istringstream in(str);
std::string word1, word2;
in >> word1;
in.seekg(0); // 回溯
in >> word2;
std::cout << "word1 = " << word1 << '\n'
<< "word2 = " << word2 << '\n';
}
成员类
sentry(哨兵)
实现为输出操作准备流的基本逻辑
(公开成员类)
--