C/C++编程:输入流类模板std :: basic_istream

1060 篇文章 308 订阅
template <class charT, class traits = char_traits<charT> >
  class basic_istream;

输入流:包装给定的抽象设备(std::basic_streambuf)并提供高层输入接口

输入流对象可以读取和解释字符序列中的输入。提供了特定的成员来执行这些输入操作(参见下面的函数)。

模板实例化

它对常用字符类型定义了二个具体类:

类型定义

istream

basic_istream<char>

wistream

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_typetraits_type::int_type 
pos_typetraits_type::pos_type一般来说,与 streampos相同
off_typetraits_type::off_type一般来说,与  streamoff相同

以及从ios_base继承的成员类型 :

event

表示事件类型的类型(公共成员类型)

event_callback

事件回调函数类型(公共成员类型)

failure

流异常的基类(公共成员类)

fmtflags

流格式标志的类型(公共成员类型)

Init

初始化标准流对象(公共成员类)

iostate

流状态标志的类型(公共成员类型)

openmode

流打开模式标志的类型(公共成员类型)

seekdir

流搜索方向标志的类型(公共成员类型)

--

公共成员函数

(构造函数)

构造对象 (公开成员函数)

(析构函数) [虚]

析构对象  (虚公开成员函数)

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();

析构输入流。

#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 对象后,它从流释出并舍弃字符,直至出现任一下列条件:

  • 输入序列中出现文件尾条件,该情况下函数调用 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::curstd::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(哨兵)

实现为输出操作准备流的基本逻辑
(公开成员类)

 

 

 

 

--

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值