c++输入输出
IO类
介绍
c++中主要的IO类有三个:iostream,fstream,sstream.iostream定义了用于读写流的基本类型,fstream定义了读写命名文件的类型,sstream定义了读写内存string对象的类型.详细的继承对应关系如下图:
条件状态(condition state)
strm::iostate strm指某一种IO类型,iostate是一种机器相关的类型,提供了表达条件状态的完整功能
strm::badbit 流已崩溃
strm::failbit 指出一个IO操作失败了
strm::eofbit 指出流到达了文件结束
strm::goodbit 用来指出流未处于错误状态.此值保证为零
s.eof() 若流s的eofbit置位,则返回true
s.fail() 若流s的failbit或badbit置位,则返回true
s.bad() 若流s的badbit置位,则返回true
s.good() 若流s处于有效状态,则返回true
s.clear() 将流s中所有条件状态位复位,将流的状态设置为有效.返回void
s.clear(flags) 根据给定的flags标志位,将流s中对应条件状态位复位.flags的类型为strm::iostate.返回void
s.setstate(flags) 根据给定的flags标志位,将流s中对应条件状态位置位.flags的类型为strm::iostate.返回void
s.rdstate() 返回流s的当前条件状态,返回值类型为strm::iostate
例:
1 | auto old_state = cin.rdstate(); // 记住cin的当前状态 |
1 | cin.clear(cin.rdstate() & ~cin.failbit & ~cin.badbit); // 将failbit和badbit复位,且保持eofbit不变 |
缓冲
导致缓冲刷新的原因可能有以下几种:
- 程序正常结束,作为main函数的return操作的一部分,缓冲刷新被执行.
- 缓冲区满时.
- 使用操纵符如endl(不附加任何额外字符的flush,附加一个空字符的ends)来显式刷新缓冲区
使用fflush(cout)也可刷新缓冲区
- 在每个输出操作之后,我们可以用操纵符unitbuf设置流的内部状态,来清空缓冲区.默认情况下,对cerr是设置unitbuf的,因此写到cerr的内容都是立即刷新的.例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/*
std::ios_base& unitbuf( std::ios_base& str );
std::ios_base& nounitbuf( std::ios_base& str );
std::cout << std::unitbuf;
*/
// modify unifbuf flag
int main () {
std::ofstream outfile ("test.txt");
outfile << std::unitbuf << "Test " << "file" << '\n'; // flushed three times
outfile.close();
return 0;
} - 一个输出流可能被关联到另一个流.在这种情况下,当读写被关联的流时,关联到的流的缓冲区会被刷新.例如,默认清空下,cin和cerr都关联到cout.因此,读cin或写cerr都会导致cout的缓冲区被刷新.例x.tie(&o)将流x关联到输出流o.
注:程序崩溃时,输出缓冲区不会被刷新
同步关系
c++中cin、cout,cerr和c的stdin、stdout、stderr都是同步的,即iostream 对象和cstdio流是同步的,同步关系如下
|C stream |iostream|
|————-|————|
|stdin | cin,wcin |
|stdout |cout,wcout|
|stderr |cerr,wcerr,clog,wclog|
可以使用
1 | bool std::ios_base::sync_with_stdio (bool sync = true); |
参数为false来取消同步来加快输出速度.(参考:探寻C++最快的读取文件的方案)
设置缓冲区大小
我们可以通过函数setbuf 和 setvbuf 自己设置输入输出流的缓冲区,需要注意的是不管程序中申请的的缓冲区实际大小为多少,setbuf都将缓冲区设置的大小为BUFSIZ(这个宏在windows下是512,ubuntu下是1024), setvbuf则可以设置缓冲区大小以及缓冲区的模式(行缓冲、全缓冲、无缓冲),需要注意的是这两个函数设置的是c的输入输出缓冲区,因为c++和c的缓冲区是同步的,所有该函数会对c++有影响
1 | void setbuf ( FILE * stream, char * buffer ); |
提升IO速度
可参考mixing cout and printf for faster output [翻译:混合cout和printf以更快的输出]和探寻C++最快的读取文件的方案
总之:
- 取消同步可以使c++中cin或cout快很多
- 尽量在io上少些格式化输出,如果必要可以先格式化输出到自己的缓冲区,然后再写入流中.如:
1
2
3
4
5
6
7
8
9
10/*puts("Hello World\n") is much faster than printf("%s", "Hellow World\n"). (Primarily due to the formatting overhead). Once you have isolated the formatted from plain text, you can do tricks like:
*/
const char hello[] = "Hello World\n";
cout.write(hello, sizeof(hello) - sizeof('\0'));
const unsigned int MAX_BUFFER_SIZE = 256;
char buffer[MAX_BUFFER_SIZE];
sprintf(buffer, "%d times is a charm.\n", 5);
unsigned int text_length = strlen(buffer) - sizeof('\0');
fwrite(buffer, 1, text_length, stdout);
参考
C++ Primer 5th
c/c++ 输入输出缓冲区
探寻C++最快的读取文件的方案
C++ 输出缓冲区的管理
C++ 输入输出流
维基百科-iostream