Iostream

iostream是C++中用于数据的流式输入与输出的头文件，属于C++标准程式库的一部分。

iostream 为 Input/Output Stream 的缩写，即是输入/输出流。“流”是一连串从I/O设备读写的字符。

## 概述

流输入输出库中的大部分类都是模板类，可以适用于不同的字符类型或操作函数（如字符比较）。常用的一些字符类型的流输入输出已经用typedef定义了相应的模板特化实例。

例如，`basic_fstream<CharT,Traits>`是文件流输入输出的实现的模板类。它的一个特化实例：`fstream`是`basic_fstream<char,char_traits<char>>`的类型别名，换句话说，这是`basic_fstream`的字符类型为`char`使用默认字符操作集的特化实例。

流输入输出库中的类可分为两类。一是定义了界面的抽象，适用于任何流类型，无论是文件流、内存缓存区流或者网络socket流。二是对具体数据源与数据汇（sink）的流的实现。C++标准库仅实现了文件流与内存缓冲区流。

流输入输出库中的类依据是否实现底层或高层操作可分为两类。实现了底层操作的类称作流缓冲区（stream buffer），处理没有任何格式化功能的字符。这些类极少被编程者直接使用。实现高层操作的类称作流，并提供了不同的格式化能力，是构建于流缓冲区之上的。

下表列出了流输入输出库的所有类的分类：

Class｜解释｜Typedefs

Stream buffers (底层功能)

`[http://en.cppreference.com/w/cpp/io/basic_streambuf basic_streambuf]`｜提供了底层的输入输出界面，被具体的数据源与汇实现。罕用｜、`streambuf` - 字符类型`char`、`wstreambuf` - 字符类型`wchar_t`

`[http://en.cppreference.com/w/cpp/io/basic_filebuf basic_filebuf]`｜提供了文件流的底层的输入输出界面，被具体的数据源与汇实现。罕用｜、`filebuf` - 字符类型 `char`、`wfilebuf` -字符类型 `wchar_t`

`[http://en.cppreference.com/w/cpp/io/basic_stringbuf basic_stringbuf]`｜提供了字符文件流的底层的输入输出界面，被具体的数据源与汇实现。罕用｜、`stringbuf` - 字符类型`char`、`wstringbuf` - 字符类型`wchar_t`

Support classes

`[http://en.cppreference.com/w/cpp/io/ios_base ios_base]`｜管理格式化信息与异常状态｜不适用

`[http://en.cppreference.com/w/cpp/io/basic_ios basic_ios]`｜管理流缓冲区｜、`ios` - 字符类型`char`、`wios` - 字符类型`wchar_t`

Input streams buffers (高层功能)

`[http://en.cppreference.com/w/cpp/io/basic_istream basic_istream]`｜包装一个抽象流缓冲区并提供高层输入界面，如格式化能力｜、`istream` - 字符类型 `char`、`wistream` - 字符类型`wchar_t`

`[http://en.cppreference.com/w/cpp/io/basic_ifstream basic_ifstream]`｜包装一个文件流缓冲区并提供高层输入界面，如打开关闭流｜、`ifstream` - 字符类型`char`、`wifstream` - 字符类型`wchar_t`

`[http://en.cppreference.com/w/cpp/io/basic_istringstream basic_istringstream]`｜包装一个字符串流缓冲区并提供高层输入界面，如访问基础字符串｜、`istringstream` - 字符类型`char`、`wistringstream` - 字符类型`wchar_t`

Output streams buffers (高层功能)

`[http://en.cppreference.com/w/cpp/io/basic_ostream basic_ostream]`｜包装一个抽象流缓冲区并提供高层输出界面，如格式化能力｜、`ostream` - 字符类型`char`、`wostream` - 字符类型`wchar_t`

`[http://en.cppreference.com/w/cpp/io/basic_ofstream basic_ofstream]`｜包装一个文件流缓冲区并提供高层输出界面，如打开关闭流｜、`ofstream` - 字符类型`char`、`wofstream` - 字符类型`wchar_t`

`[http://en.cppreference.com/w/cpp/io/basic_ostringstream basic_ostringstream]`｜包装一个字符串流缓冲区并提供高层输出界面，如访问基础字符串｜、`ostringstream` - 字符类型`char`、`wostringstream` - 字符类型`wchar_t`

Input/output streams buffers (高层功能)

`[http://en.cppreference.com/w/cpp/io/basic_iostream basic_iostream]`｜包装一个抽象流缓冲区并提供高层输入输出界面，如格式化能力｜、`iostream` - 字符类型`char`、`wiostream` - 字符类型`wchar_t`

`[http://en.cppreference.com/w/cpp/io/basic_fstream basic_fstream]`｜包装一个文件流输入输出缓冲区，并提供高层输入输出界面，如打开关闭文件｜、`fstream` - 字符类型`char`、`wfstream` - 字符类型`wchar_t`

`[http://en.cppreference.com/w/cpp/io/basic_stringstream basic_stringstream]`｜包装一个字符串流输入输出缓冲区，并提供高层输入输出界面，如访问基础字符串｜、`stringstream` - 字符类型`char`、`wstringstream` - 字符类型`wchar_t`

### 头文件

- `<ios>`包含着`ios_base`与`basic_ios`的类的定义，负责信息格式化与关联的流缓冲区。
- `<istream>`包含了`basic_istream`类模板定义，实现了格式化输入
- `<ostream>`包含了`basic_ostream`类模板定义，实现了格式化输出
- `<iostream>`包含了`basic_iostream`类模板定义，实现格式化输入输出
- `<fstream>`包含了`basic_ifstream`, `basic_ofstream`与`basic_fstream`类模板定义，实现格式化文件流的格式化输入、输出
- `<sstream>`包含了`basic_istringstream`, `basic_ostringstream`与`basic_stringstream` 类模板定义，实现格式化字符串流的输入输出
- `<iomanip>`包含了格式化manipulator
- `<iosfwd>`包含了所有的流输入输出库的前向声明（forward declaration）

## 支持类

`[http://en.cppreference.com/w/cpp/io/ios_base ios_base]`与`[http://en.cppreference.com/w/cpp/io/basic_ios basic_ios]`是两个类处理底层比特流。`ios_base`存储格式化信息与流的状态。`basic_ios`管理关联的流缓冲区。`basic_ios`通常以特化实例`ios`与`wios`出现。`basic_ios`与`ios_base`很少被程序员直接使用。通常，它们的功能通过其它派生的类，如`iostream`。

### Typedefs

名字｜描述

`ios`｜`basic_ios`的`char`类型特化

`wios`｜`basic_ios`的`wchar_t`类型特化

`streamoff`｜支持内部操作

`streampos`｜保存缓冲器指针或文件指针的当前位置

`wstreampos`｜保存宽字符版的缓冲器指针或文件指针的当前位置

`streamsize`｜流的尺寸

### 格式化操纵符（manipulator）

名字｜描述

`[http://en.cppreference.com/w/cpp/io/manip/boolalpha boolalpha]` / `[http://en.cppreference.com/w/cpp/io/manip/boolalpha noboolalpha]`｜指示流中的`bool`类型变量是否以`true`或`false`，还是以`0`或`1`形式出现

`[http://en.cppreference.com/w/cpp/io/manip/skipws skipws]` / `[http://en.cppreference.com/w/cpp/io/manip/skipws noskipws]`｜指示输入操作时空白符是否被跳过

`[http://en.cppreference.com/w/cpp/io/manip/showbase showbase]` / `[http://en.cppreference.com/w/cpp/io/manip/showbase noshowbase]`｜指示数的基数记数标志是否显示

`[http://en.cppreference.com/w/cpp/io/manip/showpoint showpoint]` / `[http://en.cppreference.com/w/cpp/io/manip/showpoint noshowpoint]`｜指示当浮点数小数部分为0时，是否显示小数部分

`[http://en.cppreference.com/w/cpp/io/manip/showpos showpos]` / `[http://en.cppreference.com/w/cpp/io/manip/showpos noshowpos]`｜指示对于正数是否显示`+`符号

`[http://en.cppreference.com/w/cpp/io/manip/unitbuf unitbuf]` / `[http://en.cppreference.com/w/cpp/io/manip/unitbuf nounitbuf]`｜指示输出是否被缓冲

`[http://en.cppreference.com/w/cpp/io/manip/uppercase uppercase]` / `[http://en.cppreference.com/w/cpp/io/manip/uppercase nouppercase]`｜指示在16进制整数或浮点数输出时是否使用大写字符

`[http://en.cppreference.com/w/cpp/io/manip/left left]` / `[http://en.cppreference.com/w/cpp/io/manip/left right]` / `[http://en.cppreference.com/w/cpp/io/manip/left internal]`｜指出对齐方式

`[http://en.cppreference.com/w/cpp/io/manip/hex dec]` / `[http://en.cppreference.com/w/cpp/io/manip/hex oct]`/ `[http://en.cppreference.com/w/cpp/io/manip/hex hex]`｜指示显示整数时的记数法

`[http://en.cppreference.com/w/cpp/io/manip/fixed fixed]` / `[http://en.cppreference.com/w/cpp/io/manip/fixed scientific]`/ `[http://en.cppreference.com/w/cpp/io/manip/fixed hexfloat]`(C++11) / `[http://en.cppreference.com/w/cpp/io/manip/fixed defaultfloat]`(C++11)｜指示浮点数显示时的记数法

## 输入/输出流

`iostream`头文件定义了输入输出流对象：`cin`, `cout`, `cerr`, `clog`分别为标准输入、输出、错误（无缓冲）、簿记（有缓冲）的流对象。都属于`std` 命名空间（namespace）。

### ostream对象

`cout`属于`ostream`类型，重载了左移位算符。cout左移位算符的运算结果为cout自身，这使得连续的左位移操作输出一串数据成为可能。`cerr`与`clog`对象是`ostream`类型。

### istream对象

`cin`是`istream`类型，重载了右位移算符。

输入设备是按照行来把数据移入流输入缓冲区。也就是说，键盘输入数据时，只有按了换行键，这一行数据才进入缓冲区，可以读取。

表达式`cin >> ival`从标准输入读入一个值。有两种情况会使一个istream对象的bool转型为false：读到EOF（文件结束标志）或遇到一个无效的值（输入流进入fail状态）。可以用该istream对象的成员函数good来测试，或者直接(bool)cin来测试。

istream对象的bool转型为false的情况下，此后的所有读入动作都是无操作（nop）。直到调用istream对象的成员函数clear来清除该对象的内部状态。

缺省情况下，输入操作符丢弃空白符、空格符、制表符、换行符以及回车。如果希望读入上述字符，或读入原始的输入数据，一种方法是使用istream的get成员函数来读取一个字符，另一种方法是使用istream的getline成员函数来读取多个字符。istream的read(char* addr, streamsize size)函数从输入流中提取size个连续的字节，并将其放在地址从addr开始的内存中。istream成员函数gcount返回由最后的get、getline、read调用实际提取的字符数。

输入流有三个函数来测试流状态：即bad, fail和eof。ignore用来抛掉制定个数的缓冲区中的字节。

其它的istream成员函数：putback( char c ) 将字符放回iostream；unget往回重置“下一个”istream项；peek返回下一个字符或EOF，但不要提取出来。

## 输出格式化

### 方法（函数）

`width(int x)`｜下一个输出的最小字符数目

`fill(char x)`｜填充字符

`precision(int x)`｜设置浮点数的有效数字的位数

### 操纵符（manipulator）

操纵符（manipulator）是使用`<<`或`>>`算子修改流的对象.

`endl`｜"end line": 流中插入换行符并刷新（flush）流的输出缓冲.

`ends`｜"end string": 向流中插入空字符（null character）并刷新（flush）流的输出缓冲.

`flush`｜强迫流的输出缓冲写出到输出设备.

`ws`｜导致输入流吃掉空白（whitespace）

`showpoint`｜指示流要显示小数点与一些数字0

头文件中`iomanip`还定义了一些manipulators。

## 批评

某些环境下并不提供共享版本的C++库。导致程序要静态编译入C++标准库，使得程序的尺寸变大。

## 示例

使用C++写成的 Hello World 程序如下所示:

```cpp
#include <iostream>
int main()
{
    std::cout << "Hello, world!" << endl; //列印出“Hello, world!”字符，并跳至下一行
    return 0;
}
```

在这段代码中，文件 iostream 中声明了程序所要输入和输出操作的有关信息。

下述代码创建一个文件'file.txt'并写入文本'Hello World'：

```cpp
#include <fstream>
int main()
{
    std::ofstream file; // 可以与 std::ofstream file("file.txt");
    file.open("file.txt");
    file << "Hello world!\n";
    file.close(); // 不必要，因程序会自动将文件关闭
    return 0;
}
```

使用在C++23新加入的`<print>`标准库的Hello World 程序如下所示：

```cpp
#include <print>
int main()
{
    std::println("Hello, world!");
    return 0;
}
```

## 外部链接

- C++ reference for input/output library
- Apache C++ Standard Library Iostreams
- Comprehensive tutorial on formatting output in C++.
- Apache C++ Standard Library Iostreams