CS106L 04 stream
recap
Uniform Initialization: Using {}
References: to use same memory
Stream Input/Output(IO)
最重要的图!!!!!!
-
coutandcin: Standard iostreams 标准输入输出流 -
cerrandclog:被用来使用输出错误,或者日志std::cerr << "the message" << std::endl; std::clog << "What are we doing here" << std::endl;
对于如下代码:
std::cout << "Hello world" << std::endl;
// "<<" insertion operator
double pi;
std::cin >> pi; //3.1415926...
// ">>" extraction operator
[!note]
std::cout是std::ostream中的一种,输出流,可以音译为"See out",看到的内容,就是输出的内容。
[!note]
std::cin是如何处理我们在控制台中输入的3.145926?这不是字符串吗?是,其会在程序中进行类型转换为double。这表明流允许以通用方式处理数据
ps:iostream 为 ostream 与 istream的集合
stringstreams
stringstreams 经常用于处理混合数据,是basic_iostream的组成成分
std::string mixText = "Liu kk 23203 19 hai KongKong";
std::stringstream ss;
ss << mixText; // or 在上一步 ss(minText)
std::string first, second;
int no, age; std::string last;
ss >> first >> second >> no >> age >> last;
std::cout << first << " " << second << " 学号:" << no << " 年龄:" << age << " 剩余的部分 " << last << std::endl;
//Liu kk 学号:23203 年龄:19 hai
[!note]
">>" 提取运算符,从
ss中提取元素,遇到空格结束提取,不包含空格,遇到\n结束istream没有。从而ss没有读取kongkong,如何完全读取剩余的部分?使用getline!
istream &getline(istream& is, string& str, char delim) // 读取input流,分隔符delim(default='\n'),并储存在str中
std::getline(ss, last);
std::cout << last << std::endl; // hai KongKong
ps:fstream 为 basic_fstring
Out streams
"<<" 符号意思把内容送到输出流,输出流中的字符存储在中间缓冲区中在被冲到目的地之前。缓存区是为了提高效率,防止过多的IO操作。
我们熟悉的std::cout是行缓冲,缓冲区中的内容不显示在外部源上,直到冲洗发生。
double tao = 6.28;
std::cout << tao; // 这一步没有flush在控制台
std::cout << std::flush; // flush冲洗在控制台,控制台的实际类型为string
std::cout << std::endl; // 也flush冲洗在控制台same '\n' + flush;
for (int i=1; i <= 5; ++i) {
std::cout << i << std::endl;
}
其过程如下,切记std::endl可以flush中间缓冲区,是'\n' + flush操作
。
| 1 | '\n' |
|---|
...
| 2 | '\n' |
|---|
.......
| 5 | '\n' |
|---|
观察过程,浪费了那么大的中间缓冲区,而且过多flush操作消费是昂贵的。std::cout << endl;是'\n' + flush操作,每一次冲洗操作的花费是昂贵的。那么直接存入字符即可。
for (int i=1; i <= 5; ++i) {
std::cout << i << '\n';
}
| 1 | '\n' | 2 | '\n' | 3 | '\n' |
|---|
[!note]
C++ 会采用自动冲洗,当中间缓存区满了,自动冲洗操作。但是在没有禁用同步流的情况下,依然会冲洗操作,采用禁用同步流可以达到目的。如果没有禁用同步流,
\n依然会类似 C 中的操作flush呈现在 C++ 中。
同步流操作
一般情况下,C、C++的I/O操作是同步的,这保证了输入输出的顺序性。采用如下代码可以禁用同步流,也就是禁用C的stdio.h标准库来禁用同步操作。
std::ios::sync_with_stdio(false);
std::cout << YES!MORE FAST! << '\n'; //Right!
[!WARNING]
特别注意,这将会导致一些出错,尤其是混合使用C和C++的输入输出流,特别是并发输出顺序。
File stream
- is_open() 检查是否打开文件
- open() 打开文件
- close() 关闭文件
- fail() 检查是否坏掉
如下代码,文件只读入了test,发生了截断Truncate
std::ofstream ofs("truncate.txt");
if (ofs.is_open()) {
ofs << "Hello CS106L!" << '\n';
}
ofs.close();
ofs << "this will not get written"; // 不会响应失败
// to append instead of truncate!
ofs.open("truncate.txt");
ofs << "test";
如何解决,采用std::ios::app:Basically app always seeks to the end before writing anything
std::ofstream ofs("append.txt");
if (ofs.is_open()) {
ofs << "Hello CS106L!";
}
ofs.close();
ofs << "this will not get written";
// to append instead of truncate!
ofs.open("append.txt", std::ios::app);
ofs << "this will though! It’s open again";
ofs.close();
cin stream
输入缓存区,当遇到如下冲刷缓存区并保留:
- ' ' // 单个空格
- \t // 制表符
- \n 换行字符
如何读取人名,带有空格的,如下:
double pi;
std::cin >> pi;
std::string name;
std::getline(std::cin, name); // 默认deilm是 '\n'
[!note]
当我们输入
pi时,缓存区留下\n这与getline操作相遇会进行清除换行符,进而结束操作,没有任何读入到变量name中。getline会清除\n。
解决方案如下:双getline
double pi;
std::cin >> pi;
std::string name;
std::getline(std::cin, name);
std::getline(std::cin, name); // 默认deilm是 '\n'
Don’t use getline() and std::cin() together, unless you really really have to!
End...