【C++】第九章:IO流
一、C语言的输入输出
在C语言中用到的输入输出方式就是scanf ()与printf()。
这些缓冲区(流)会有一些缓冲机制,如行缓冲,但流中遇到\n号时,就会自动刷新到相关的文件中。
解释一下输入输出缓冲区的理解:
1.可以屏蔽掉低级I/O的实现,也就是IO系统调用。 如read,open,write。它们这些系统调用函数,是直接与文件打交到的,没有缓冲,没有流的概念。
2.可以使用这部分的内容实现“行”读取的行为,通过解析缓冲区的内容,返回一个“行”。
二、流的概念
C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存) 输入和从内存向外部输出设备(显示器)输出的过程。这种输入输出的过程被形象的比喻为“流”。
先要明确的是,在标准IO里面,这些函数都是对流的操作,那么什么是流呢?可以把流直观地理解为一段缓冲区,如stdin便准输入流,可以把它理解为一段缓冲区,每个流都与一个文件相关连了,stdin流也不例外,它默认与屏幕这个文件(UNIX中一切皆文件的思想)相连。
三、C++的IO流
在C++的IO中有很庞大的类库支持,通过继承关系衍生出了很多不同的输入输出的类。
1.C++标准IO流
C++标准库提供了4个全局流对象cin 、cout 、cerr 、clog 。
-
使用cout 进行标准输出,即数据从内存流向控制 台(显示器)。 -
使用cin 进行标准输入即数据通过键盘输入到程序中。 -
cerr 用来进行标 准错误的输出。 -
clog 进行日志的输出。 从上图可以看出,cout 、cerr 、clog 是ostream 类的三个不同的 对象。 举个例子:
std::cout << "hello world";
std::cerr << "hello world";
std::clog << "hello world";
注意:C++的标准IO都是以空格 或者\n(回车换行) 为结束符的,也就是缓冲区中内容由这两个符号隔开,遇到空格或者回车的时候,就将缓冲区中的内容刷新到屏幕上。因此就形成了“行”的概念。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
cin >> str;
cout << str;
cin >> str;
cout << str;
return 0;
}
如果想要获取一行的信息的时候,可以使用getline() 函数。因为getline() 函数只会以\n ,也就是回车为结束符,遇到空格还是会继续的。
getline(cin, str);
cout << str;
补充:在多组数据要输入的时候。
1.一般C语言就是使用scanf() ,知道遇到文件结束符EOF 也可以使用ctrl + c
while (scanf("%d", &x) != EOF)
2.在C++中可以直接使用cin
while (cin >> x)
当没有数据的时候,cin 对象会返回一个bool 值。即operator bool() const 函数将对象转化为bool 然后返回false 使得while 结束。
2.C++文件IO流
C++根据文件内容的数据格式分为二进制文件和文本文件。采用文件流对象操作文件的一般步骤:
①.定义文件流对象
定义的时候,需要包含头文件#include <fstream>
文件流 | 作用 |
---|
ofstream | 创建文件并向文件中写入信息 | ifstream | 从文件中读取信息 | fstream | 可以创建文件并写入也可以读取文件中的信息 |
#include <fstream>
using namespace std;
int main()
{
ofstream outFile;
ifstream inFile;
fstream File;
return 0;
}
②.打开文件
在从文件读取信息或者向文件写入信息之前,必须先打开文件。
打开的方式:使用open() 函数进行文件打开。如下:
ofstream outFile;
outFile.open("test.txt");
ifstream inFile;
inFile.open("test.txt");
fstream file;
file.open("test.txt");
文件打开的方式:
除了默认的打开方式还有很多的文件打开方式:
模式 | 描述 |
---|
ios::in | 以读的方式打开 | ios::out | 以写的方式打开 | ios::trunc | 如果此文件已经存在, 就会打开文件之前把文件长度截断为0 | ios::app | 尾部追加方式打开 | ios::ate | 文件打开后,定位到文件末尾 | ios::binary | 以二进制方式打开 |
举例:如果想要进行写的操作,又想从尾部开始写,就可以使用位操作符| 组合起来:
ofstream outFile;
outFile.open("test.txt", ios::out | ios::app)
③.对文件进行读写操作
成员函数 | 功能描述 |
---|
put | 插入一个字符到文件中 | wirte | 插入一段字符串到文件中 | get | 从文件中提取字符 | read | 从文件中提取多个字符 | tellg | 获取当前字符在文件当中的位置 | seekg | 设置对文件进行操作的位置(三个位置beg cur end ) | operator<< | 数据输出 | operator>> | 数据输入 |
举例:想要打开一个文本文件,在写入数据之后,再打开这个文件,读取数据。
void Write()
{
ofstream outFile;
outFile.open("test.txt", ios::out);
char str[] = "hello zhy";
outFile.write(str, strlen(str));
outFile.put('~');
outFile.close();
}
void Read()
{
ifstream inFile;
inFile.open("test.txt", ios::in);
inFile.seekg(0, inFile.end);
int len = inFile.tellg();
inFile.seekg(0, inFile.beg);
char str[20];
inFile.read(str, len);
inFile.close();
}
④.关闭文件
使用close() 函数对文件对象进行关闭。
fstream file;
file.open("test.txt");
file.close();
3.operator<< 和 operator>>写入和读取
在C++中可以直接使用流这样的概念和operator<< 和operator>> 这样的函数,就可以完成以上四部操作。
举例:
void Write()
{
ofstream outFile("test.txt");
outFile << "hello zhy~";
}
void Read()
{
ifstream inFile("test.txt");
char str[20];
inFile >> str;
}
总结:显然使用流对象的方式更加的形象,也更加简洁。
四、stringstream流
在C语言中我们需要使用向sscanf() ,sprintf() 这样的函数将整形的数据转化成为字符串类型的格式。在C++中同样提供了流对象这样我的概念去简化转化的操作。
在<sstream> 的头文件下,有这样三个类可以帮助我们:
类 | 操作场景 |
---|
ostringstream | 输入 | istringstream | 输出 | stringstream | 输入+输出 |
一般我们都使用stringstream 对整形变量或字符串进行操作。
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
int num = 100;
stringstream ssin;
ssin << num;
string str;
ssin >> str;
return 0;
}
stringstream 对象可以使用str() 函数,将stringstream 对象中的内容以字符串的形式返回;或者可以使用str() 函数对stringstream 对象中的内容进行覆盖。
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
int num = 100;
stringstream ssin;
ssin << num;
cout << ssin.str();
ssin.str("hello");
cout << ssin.str();
return 0;
}
使用的注意事项:
1.stringstream 实际是在底层维护了一个string 类型的对象用来保存结果。
2.stringstream 在转换结尾时(即最后一个转换后),会将其内部状态设置为badbit ,因此在下一次转换前必须调用clear 将状态重置为goodbit 才可以转换,但clear 不会将stringstream 底层的string 对象清空,而是清空对象的状态。
3.可以使用s.str("") 的方式将stringstream 底层的string 对象设置为空字符串,否则多次转换时,会将结果全部累积在底层string 对象中。
4.获取stringstream 转换后的结果有两个方法,一是使用>> 之间从流当中提取,二是使用s.str( ) 获取stringstream 底层的string 对象。
5.stringstream 使用string 类对象代替字符数组,可以避免缓冲区溢出的危险,而且其会对参数类型进行推演,不需要格式化控制,也不会存在格式化失败的风险,因此使用更方便,更安全。
|