10. C++IO流
C语言的输入输出
在C语言中我们使用最频繁的输入输出方式是 scanf () 与 printf():
- scanf():从标准输入设备 (键盘) 读取数据,并将值存放在变量对应的内存空间中。
- printf():将指定的文字/字符串输出到标准输出设备 (显示器)。(注意宽度输出和精度输出控制)
实际上C语言借助了相应的缓冲区来进行输入与输出。如下图所示:
对输入输出缓冲区的理解:
- 缓冲区的存在可以屏蔽掉低级I/O的实现;由于低级I/O的实现依赖操作系统本身内核的实现,所以如果能够屏蔽这部分的差异,就可以很容易写出可移植的程序。
- 可以使用这部分的内容实现 “行” 读取的行为;对于计算机而言是没有 “行” 这个概念,有了这部分,我们就可以定义 “行” 的概念,然后解析缓冲区的内容,返回一个 “行”。
注:C语言除了有输入输出接口 scanf 和 printf,还有文件操作读写接口 fread/fwrite、fscanf/fprintf,以及字符串序列化反序列化接口 sprintf/snprintf/sscanf。
流的概念
流就是若干字节组成字节序列,流操作从一个到另一个移动的过程.是对一种有序连续且具有方向性的数据( 其单位可以是bit/byte/packet )的抽象描述。流的特点是有序连续且具有方向性。
C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存向外部输出设备(显示器)输出的过程。这种输入输出的过程被形象的比喻为 “流”。
为了实现这种流动,C++定义了I/O标准类库,这些每个类都称为流/流类,用以完成某方面的功能。
流中的内容:二进制数据 ASCII码
流类体系
C++中用类实现所有流类操作
-
标准的输入输出流
- C++格式控制
-
字符流
-
文件流
#include <iostream> //istream ostream
#include <fstream> //ifstream ofstream
#include <strstream> //istringstream ostringstream
using namespace std;
int main()
{
fstream out;
ifstream iin;
return 0;
}
标准输入输出流
- 重定向: C语言 freopen函数介绍
| 对象 | 类型 | 作用 |
|---|---|---|
| cin | 标准输入 | 从键盘读取,可以重定向 |
| cout | 标准输出 | 输出到控制台,可以重定向 |
| cerr | 标准错误输出 | 输出到控制台,不可以重定向 |
| clog | 标准错误输出 | 输出到控制台,可重定向 |
#include <iostream>
using namespace std;
int main()
{
cout << "标准输出" << endl;
cerr << "标准错误" << endl;
clog << "标准错误" << endl;
return 0;
}
- 字符和字符串输入
- cout成员函数
- put() : 输出一个字符
- write(): 输出字符串
- cin成员函数
- get():输入一个字符
- getline: 输入一个字符串
- cout成员函数
#include <iostream>
using namespace std;
int main()
{
cout << "标准输出" << endl;
cerr << "标准错误" << endl;
clog << "标准错误" << endl;
//字符输入
cout << "字符输入:" << endl;
int userKey = cin.get();
cout.put(userKey);
char str[10] = { "" };
cout << "字符串输入:" << endl;
while (getchar() != '\n');
cin.getline(str, 10); //10个长度包含\0
cout << str << endl;
cout.write(str, 10);
return 0;
}
- C++格式控制
- 包含头文件: iomanip
- 通过对象的形式,一种通过成员的函数形式
| 对象形式 | 实际含义 |
|---|---|
| setbase(n) | 设置多少进制输出整数(参数是8和16) |
| setw(n) | 设置输出数据宽度(默认对齐是右对齐,不足补空格) |
| setiosflags(ios::left) | 设置对齐方式: ios::left ,ios::right |
| setprecition(n) | 单纯使用是控制有效位数,如果控制小数位数结合fixed |
| setfill(n) | 填充字符 |
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
//进制输出
cout << setbase(16) << 32 << endl;
cout << setbase(8) << 32 << endl;
cout <<showbase<< hex << 32 << endl;
cout << dec << 32 << endl;
cout << noshowbase<<oct << 32 << endl;
//cout << setbase(2) << 32 << endl; //无效
//默认右对齐
cout << setw(10) << "姓名" << setw(10) << "年龄" << setw(10) << "编号" << endl;
cout << setw(10) << "小芳" << setw(10) << 17 << setw(10) << 119911 << endl;
cout << setiosflags(ios::left);
cout << setw(10) << "姓名" << setw(10) << "年龄" << setw(10) << "编号" << endl;
cout << setw(10) << "小芳" << setw(10) << 17 << setw(10) << 119911 << endl;
cout << setprecision(4) << 300.12345 << endl; //直接用控制的是有效位数
cout << fixed<<setprecision(4) << 300.12349 << endl; //小数位数
cout << setiosflags(ios::scientific) << 300.12345 << endl;
//所有的格式控制存在成员函数的调用形式
cout.width(8);
cout << "姓名";
cout.width(8);
cout << 1 << endl;
cout.precision(4);
//取消上述格式
cout <<resetiosflags <<300.333 << endl;
bool num = 1;
cout << boolalpha << num << endl; //true和false形式输出bool类型
return 0;
}
字符流
-
包含头文件: sstream
-
istringstream
-
ostringstream
-
stringstream
-
-
一般处理字符流的时候用的是stringstream类型的对象
-
获取字符流中的stirng
-
string str(); //获取string
-
void str(const string& str) //重置流对象中字符串
-
-
字符流做什么
- 数据类型的转换
- 数据的分割
#include <sstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
stringstream stream("ILoveyou");
cout << stream.str() << endl;
char str[20] = "";
stream >> str;
cout << str << endl;
stream.str(""); //清除
//数据类型转换
//整数转字符串,字符串转数字
string num = to_string(123);
cout << num << endl;
int inumber = 12123;
char result[20] = { "" };
stringstream buf(result);
buf << inumber;
buf >> result;
cout << result << endl;
stringstream strNum("12345435");
int dataNum = 0;
strNum >> dataNum;
cout << dataNum << endl;
//数据切割(流中默认空格作为单一数据的间隔)
stringstream ip("ip: 192.168.1.1");
char strip[20] = { "" };
ip >> strip; //ip: 拿出来
int ipNum[4];
char userKey;
ip >> ipNum[0];
ip >> userKey;
ip >> ipNum[1];
ip >> userKey;
ip >> ipNum[2];
ip >> userKey;
ip >> ipNum[3];
for (int i = 0; i < 4; i++)
{
cout << ipNum[i] << "\t";
}
cout << endl;
//注意点: 流在做转换的,必须调用clear清除处理
buf.clear();
buf << inumber;
buf >> result;
cout << result << endl;
return 0;
}
文件操作流
- 包含头文件: fstream
- ofstream: 打开文件只能写操作
- ifstream: 打开文件只读操作
- 一般大家创建一个fstream对象,可读可写
- 打开文件
- 构造的方式,带参数构造函数:const char* URL,ios::openmode mode
- 成员函数方式: void open(const char* URL,ios::openmode mode)
- 判断文件打开是否成功
- !is_open()函数判断是否打开成功 ,!is_open()是1的打开失败
- !文件对象 .!对象是1打开失败
| 读写方式 | 作用 |
|---|---|
| ios::in | 读的方式打开文件 |
| ios::out | 写的方式打开文件 |
| ios::app | 追加写文件 |
| ios::ate | 打开已有文件,指针在文件末位 |
| ios::trunc | 文件不存在具有创建方式 |
| ios::binary | 二进制打开,默认打开方式ASCII码 |
| ios::nocreate | 不创建 |
| ios::noreplace | 不替换 |
组合方式: 用位或, 可读可写: ios::in|ios::out
- 关闭文件
- close关闭文件
- 文件读写
- 直接采用>> <<符号进行读写
- 采用成员函数读写:read函数和write成员函数
- 文件指针移动
- ifstream文件指针
- ifstream& seekg(long int pos);
- ifstream& seekg(long int pos,ios_base::seekdir begin);
- ofstream文件指针
- ofstream& seekp(long int pos);
- ofstream& seekp(long int pos,ios_base::seekdir begin);
- begin:
- ios::beg 开始位置
- ios::cur 当前位置
- ios::end 结束位置
- ifstream文件指针
#include <iostream>
}
file << name<<" "<< age<<" "<< num<<endl;
file.close();
}
void readFile(string fileName)
{
fstream file(fileName, ios::in);
if (!file)
{
cout << "打开文件失败!" << endl;
return;
}
while (true)
{
MM temp;
file >> temp.name >> temp.age >> temp.num;
if (file.eof())
{
break;
}
temp.print();
}
file.close();
}
protected:
string name;
int age;
int num;
};
void asciiRWFile(string readFile, string writeFile)
{
//流的方式
//字符或者字符串的
fstream read(readFile, ios::in);
fstream write(writeFile, ios::out);
while (!read.eof())
{
char userkey = read.get(); //getline()
write.put(userkey); //write()函数
}
read.close();
write.close();
}
//二进制读写
void binaryRWFile(string readFile, string writeFile)
{
fstream r(readFile, ios::in | ios::binary);
fstream w(writeFile, ios::out | ios::binary);
while (!r.eof())
{
char str[1024] = {""}; //缓冲区
r.read(str, 1024);
w.write(str, strlen(str)); //长度写多少就写入文件多少
}
r.close();
w.close();
}
//文件指针移动
int getSize(string fileName)
{
fstream read(fileName, ios::in | ios::binary);
read.seekg(0, ios::end);
int size = read.tellg();
read.close();
return size;
}
int main()
{
//打开文件测试
//fstream file("xxoo.txt",ios::in|ios::out|ios::trunc);
//等效下面两行
fstream file;
file.open("xxoo.txt", ios::in | ios::out | ios::trunc);
if (!file || !file.is_open())
{
cerr << "文件打开失败" << endl;
}
file.close();
MM mm("xxx", 18, 1001);
mm.saveFile("mm.txt");
mm.readFile("mm.txt");
asciiRWFile("mm.txt", "xxoo.txt");
binaryRWFile("xxoo.txt", "rw.txt");
cout << "size:" << getSize("size.txt") << endl;
return 0;
}