【C++】第九章:IO流
文章目录
- 【C++】第九章:IO流
- 一、C语言的输入输出
- 二、流的概念
- 三、C++的IO流
- 1.C++标准IO流
- 2.C++文件IO流
- ①.定义文件流对象
- ②.打开文件
- ③.对文件进行读写操作
- ④.关闭文件
- 3.operator<< 和 operator>>写入和读取
- 四、stringstream流
一、C语言的输入输出
在C语言中用到的输入输出方式就是scanf ()与printf()。
-
scanf(): 从标准输入设备(键盘)读取数 据,并将值存放在变量中。
-
printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)。
C语言借助了相应的缓冲区来进行输入与输出。
这些缓冲区(流)会有一些缓冲机制,如行缓冲,但流中遇到\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; // 输入hello world
cout << str; // 输出 hello
cin >> str; // 不会等待输入,而是将在空格后面的world直接放入
cout << str; // 输出world
// 最后看到的效果就是输入hello world,然后直接输出helloworld(其中的空格被缓冲区获取了)
return 0;
}
如果想要获取一行的信息的时候,可以使用getline()
函数。因为getline()
函数只会以\n
,也就是回车为结束符,遇到空格还是会继续的。
getline(cin, str);// 从cin中获取数据到str中,假设输入hello world
cout << str; // 输出hello world
补充:在多组数据要输入的时候。
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"); // ofstream默认以写的方式打开文件
ifstream inFile;
inFile.open("test.txt"); // ifstream默认以读的方式打开文件
fstream file;
file.open("test.txt"); // fstream默认以读+写的方式打开文件
文件打开的方式:
除了默认的打开方式还有很多的文件打开方式:
模式 | 描述 |
---|---|
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)); // 将str写入文件当中
outFile.put('~'); // 将~写入文件
outFile.close();
}
void Read()
{
ifstream inFile;
inFile.open("test.txt", ios::in); // 以读的方式打开文件
inFile.seekg(0, inFile.end); // 定位到文件的末尾
int len = inFile.tellg(); // 定位当前的位置,因为当前在文件的末尾,所以len就是文本的长度
inFile.seekg(0, inFile.beg); // 定位会文件的开头
char str[20];
inFile.read(str, len); // 读取len个字符到str中
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; // 将100输入给ssin当中
string str;
ssin >> 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; // 将100输入给ssin当中
cout << ssin.str(); // 以字符串的形式输出100
ssin.str("hello"); // 将hello覆盖在ssin中
cout << ssin.str(); // 输出hello
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
类对象代替字符数组,可以避免缓冲区溢出的危险,而且其会对参数类型进行推演,不需要格式化控制,也不会存在格式化失败的风险,因此使用更方便,更安全。