输入输出流 ######################################## 当谈及输入输出流时,需要牢记的是:输入输出是相对于程序而言的,比如读文件相当于向程序输入数据,写文件相当于程序向磁盘输出数据。 本章节将会叙述 标准 IO 流、文件流、字符串流 以及相关的迭代器 标准 IO 流 **************************************** 所谓标准 IO,包含三个部分:标准输入流、标准输出流、标准错误流, C++ 将其映射为四个类对象 .. csv-table:: :header: 流名称, 作用 cin, 标准输入流(stdin) cout, 标准输出流(stdout) cerr, 无缓冲的标准错误流(stderr) clong, 有缓冲的标准错误流(stderr) 用于宽字节标准 IO 的类对象为:wcin, wcout, werr, wclong 一般来说,要使用标准 IO 流,需要包含的头文件为 istream, ostream 或者 iostream .. note:: 实际上,istream, ostream 等只是 C++ 创建的别名: .. code-block:: cpp typedef basic_istream istream; typedef basic_ostream ostream; typedef basic_iostream iostream; 标准 IO 流是在 C++ 输入输出流中是最重要的流,文件流和字符串流都直接或者间接继承自标准流,因此,标准 IO 流对于其他流也是适用的。 标准 IO 流的打开模式 ======================================== 标准 IO 流定义了多种打开模式: .. csv-table:: :header: 模式, 作用 ios_base::app, 追加模式(append) ios_base::ate, 打开文件并定位到文件尾部(at end) ios_base::trunc, 截断模式 ios_base::binary, 以二进制模式打开或写入流,该行为系统相关 ios_base::in, 读 ios_base::out, 写 尽管以上模式定义于 ``ios_base::`` 中,但是一般使用 ``ios::`` 以方便书写。 标准 IO 流的状态 ======================================== 一个流总是处于以下状态之一: .. csv-table:: :header: 状态名, 含义 good(), 上一个流操作成功 eof(), 到达流末尾 fail(), 非致命错误,上一个流操作失败(比如读取数组却得到一个 'X') bad(), 致命错误(比如磁盘读取错误) IO 流只有在 good() 状态下才可以进行操作。否则对其操作全部无效。当一个流被当作条件时,其返回结果为 good() 的值: .. code-block:: cpp for(char s = 'a'; cin>>s;){ if( s == 'f') cin.setstate(ios::failbit); cout<>x 根据 x 的类型从 in 读取数据并存入 x 中。 getline(istream&in, string&s) 并从 in 中读取一行,写入到 s 中。不保留换行符 in.get() 返回值为 int, 到达末尾时返回 EOF,提前到达置 eofbit为真 in.getline(char*s, int n) 从 in 中读取 n 个字符并写入到 s 中,不保留换行符 in.read(s, n) 从 in 中读取 n 个字符并写入到 s 中,不会自动添加 '\0' ============================== ================================================== 尽量选择 ``in>>x`` 和 ``getline()``,而不是其他更加底层的函数。 另外,还有一个 ignore: ============================================== istream& ignore(int n = 1, int delim = EOF) ============================================== ignore 会跳过 n 个字符或遇到 delim 为止 输入输出格式控制 **************************************** iomanip 无格式输入函数 **************************************** 输入流的 :abbr:`无格式输入函数 (UnformattedInputFunction )` 其行为如下: - 在存储周期内自动构建一个 noskipws 设置为 true 的 **basic_istream::sentry** 。 - 若输入流的 eofbit 和 badbit 被同时设定,则 failbit 也会设置,如果输入流的 failbit 允许抛出异常,则还会抛出 ios_base::failure - 如果可能,刷新 std::tie 的输入流 - 通过调用 sentry::operator bool() 检查 sentry 的情况,这与 basic_ios::good 的效果相同。 - 如果 sentry 返回 ``false`` 或 sentry 在构造时抛出异常: - 设置输入流已经提取的字符数量( gcount )为 0 - 如果函数被用于向一个 charT 数组写入数据,向数组的第一个位置写入一个空字符 - 如果 sentry 返回值为 true ,其行为与调用 ``rdbuf()->sbumpc()`` 或 ``rdbuf()->sgetc()`` 行为形同。 - 若到达流的末尾(通过调用 ``rdbuf()->sbumpc()`` 或 ``rdbuf()->sgetc()`` ),设置 eofbit 。若 eofbit 的异常被打开,则抛出 ios_base::failure - 如果在输入时抛出了异常,置 badbit 。若允许异常,则抛出 ios_base::badbit - 若没有异常抛出,设置输入流的已提取字符数( gcount ) - 无论如何(无论是被异常终止还是被返回), sentry 的析构函数总是在离开函数时被调用。 以下标准库函数是 *无格式输入函数* - std::getline 不会修改 gcount. - basic_istream::operator>>(basic_streambuf*) - basic_istream::get - basic_istream::getline - basic_istream::ignore - basic_istream::peek - basic_istream::read - basic_istream::readsome - basic_istream::putback 它会首先清除 eofbit - basic_istream::unget 它会首先清除 eofbit - basic_istream::sync 不会修改 gcount - basic_istream::tellg 不会修改 gcount - basic_istream::seekg 首先清除 eofbit 而且不会修改 gcount - std::ws 不会修改 gcount endl **************************************** endl 可以用来刷新流。如果不刷新流,那么抛出异常后,中间所有缓冲区中的内容都会丢失