输出输出流
“流”是一种抽象的形态,指的是计算机里的数据从一个对象流向另一个对象。
流类库的结构
ios_base类,表示流类的一般特征。
ios类,继承与ios_base类,其中包含一个指向streambuf对象的指针成员。
ostream类,ios的派生类,提供了输出方法。
istream类,ios的派生类,提供了输入方法。
iostream,是istream和ostream的子类,既可以输入又可以输出。
文件处理相关类
ifstream,提供文件输入方法。
ofstream,提供了文件输出方法。
fstream,提供了文件输入和输出方法。
cout与cin
在输入输出流类库中,操作符>>和<<被重载用于进行数据的输入和输出。
cout输出
<<, 插入运算符。
put,ostream类的方法,用于字符的输出。
write,ostream类的方法,用于字符串的输出。
int main()
{
// put输出字符
cout.put('A');
cout.put(97); // 输出 'a'
cout.put('B').put('C').put('\n');
// write输出字符串,第二个参数指定输出的长度
char c[] = "Hello C++!";
cout.write(c, strlen(c)).put('\n'); // cout << c << endl;
cout.write(c, 5).put('\n');
c[10] = 'X';
cout.write(c, 11).put('\n'); // write 输出指定长度的字符串,即使字符数组没有'\0'也能正常输出。
cout << c << endl; // << 输出到第一个字符串结束标识,如果字符数组没有'\0'会输出乱码。
return 0;
}
cin输入
>>,提取运算符。
get,istream类的方法,提取字符。
getline,istream类的方法,提取一行字符。
/*
cin 的工作方式:
先检查缓冲区中是否有数据,有则提取,无则提示输入。
>> 与get、getline的主要区别
>> 提取时会从第一个非' '和'\n'的字符开始提取,之前的' '和'\n'会被忽略掉。
get、getline提取数据时,不会忽略任何字符。
*/
int main()
{
char c1;
char c2[30];
cout << "使用 >> 提取一个字符:" << endl;
cin >> c1;
cout << "c1: " << c1 << endl;
cout << "使用 >> 提取字符串:" << endl;
cin >> c2;
cout << "c2: " << c2 << endl;
cout << "使用 get 方法提取字符:" << endl;
cin.ignore(); // 忽略一个字符
cin.get(c1);
cout << "c1: " << c1 << endl;
cout << "使用 getline 方法提取一行字符串:" << endl;
cin.ignore();
/*
getline可以读取一行数据(以换行符结束,允许包含空格)
第一个参数是存放字符串的首地址,第二个参数是要读取字符串的长度。
*/
cin.getline(c2, 30);
cout << "c2: " << c2 << endl;
return 0;
}
格式化输入输出
两种格式化的实现方式:
流控制符,setw、setfill、setprecision、hex、oct、dec等,需要包含iomanip头文件。
成员函数,width、fill、precision等,不需要包含iomanip头文件就可以使用。
输出宽度控制,setw和width, 只对下一次有效。
设置填充字符,setfill和fill,永久有效,直到被更改。
fill可以返回当前填充字符,setfill不能。
输出精度控制,setprecison和precision,永久有效,直到被更改。
precison可以返回当前填充字符,setprecision不能。
设置显示的数制
指定数制显式输出数据,永久有效直到被修改。
int main()
{
// 控制输出宽度
cout << "1234567890" << endl;
// 使用流控制符输出宽度
cout << setw(6) << 4.5 << endl;
cout << 4.5 << endl;
cout << setw(5) << 4.5 << endl;
// 使用width成员函数控制输出宽度
const char* c1[3] = { "abc", "abcde", "abcdefgh" };
for (int i = 0; i < 3; i++)
{
cout.width(6); //调用后生效一次
cout << c1[i] << endl;
}
// 设置填充字符
cout << endl << "1234567890" << endl;
// 使用流控制符填充字符
cout << setfill('*');
for (int i = 0; i < 3; i++)
{
cout.width(10);
cout << c1[i] << endl;
}
// fill可以返回当前填充字符,本例中返回*
char c2 = cout.fill('#');
for (int i = 0; i < 3; i++)
{
cout.width(10);
cout << c1[i] << endl;
}
// 恢复fill设置填充字符之前的填充字符
cout.fill(c2);
for (int i = 0; i < 3; i++)
{
cout.width(10);
cout << c1[i] << endl;
}
// 控制输出精度
double PI = 3.141592653;
cout << PI << endl;
// 流控制符控制精度
cout << setprecision(10) << PI << endl;;
// 方法控制精度
int op = cout.precision(4); // precision方法可以返回当前精度
cout << PI << endl;
cout.precision(op);
cout << PI << endl;
// 控制符hex,oct,dec控制显式不同的进制
int n = 100;
cout << "十进制" << n << endl;
cout << "十六进制" << hex << n << endl;
cout << "八进制" << oct << n << endl;
cout << "十进制" << dec << n << endl;
return 0;
}
文件读写
读写文件的一般过程,打开文件,读/写文件,关闭文件。
打开文件
定义流对象并打开文件的两种方法
用默认构造函数创建对象,然后调用open方法打开文件。
使用有参构造函数,定义对象同时打开文件。
文件的打开方式
写入文件
<< ,插入运算符。
put方法,写入一个字符。
write方法,写入字符数组,还可以用于整体输出自定类型的数据。
int main()
{
// 用默认构造函数创建对象,然后调用open方法打开文件
ofstream myOut;
myOut.open("D:\\test.txt");
// 写入数据
myOut << "Hello";
myOut.put(' ').write("ios", 3).put('\n');
// 关闭输出流
myOut.close();
// 使用有参构造函数
ofstream myOut1("D:\\test.txt", ios_base::app);
myOut1 << "Hello Student!" << endl;
myOut1.close();
return 0;
}
读取文件
>> ,提取运算符。
get方法,读取一个字符。
getline方法,读取一行字符。
read,读取字符数组,还可以用于整体读取自定义类型的数据。
#include <iostream>
#include <fstream> // 读写文件都要导入fstream
using namespace std;
int main()
{
char c[10], c1;
int n;
ifstream myIn("D:\\data.txt");
// 读取字符串
myIn >> c;
cout << "c: " << c << endl;
// 读取数字1, n是整型
myIn >> n;
cout << "n: " << n << endl;
/*
读取字符'1', c1是字符型
myIn >> c1;
cout << "c1: " << c1 << endl;
*/
// 提取字符串abcde
myIn >> c;
cout << "c: " << c << endl;
// 读取空格。get不会忽略空格和换行符。
myIn.get(c1);
/*
读取f。提取运算符会忽略空格和换行符。
myIn >> c1;
*/
cout << "c1: " << c1 << endl;
myIn.getline(c, 10);
cout << "c: " << c << endl;
myIn.close();
return 0;
}
读写二进制文件
#include <iostream>
#include <fstream>
using namespace std;
class MyClass
{
private:
int length;
int width;
public:
MyClass(int length, int width)
{
this->length = length;
this->width = width;
}
void show()
{
cout << length << ", " << width << endl;
}
};
int main()
{
MyClass mc1(10, 10), mc2(20, 20);
mc1.show();
mc2.show();
// 把mc1的属性值以二进制形式写入文件test1.txt
ofstream myOut("D:\\test1.txt", ios_base::binary | ios_base::out);
/*
write函数的参数时字符指针,要写入数据的长度
(char*)&mc1 强制转换mc1的地址为字符指针;
sizeof(mc1)获取mc1的数据占用的内存空间的大小。
*/
myOut.write((char*)&mc1, sizeof(mc1));
myOut.close();
// 从test1.txt中读取二进制数到mc2中
ifstream myIn("D:\\test1.txt", ios_base::binary | ios_base::in);
myIn.read((char*)&mc2, sizeof(mc2));
myIn.close();
mc2.show();
return 0;
}
文件读写位置指针
与ofstream对应的是写位置指针,指定下一次写数据的位置
seekp函数,移动写指针,p是put的缩写。
tellp函数,返回写指针的位置。
与ifstream对应的是读位置指针,执行下一次读数据的位置
seekg函数,移动读指针,g是get的缩写。
tellg,返回读指针位置。
seekg(n),n >0移动到文件的第n个字节后,n = 0移动到文件的起始位置。
seekg(n, ios::beg),从文件起始位置向后移动n个字节,n是大于或等于0的整数。
seekg(n, ios::end),从文件结尾位置向前移动n个字节,n是小于或等与0的整数。
seekg(n, ios::cur),从文件当前位置向前或后移动n个字节,整数和负数移动顺序相反。
streampos, tellg的返回值类型,表示文件位置,可以看成整型数据。
#include <iostream>
#include <fstream>
using namespace std;
class MyClass
{
private:
int length;
int width;
public:
MyClass(int length, int width)
{
this->length = length;
this->width = width;
}
void show()
{
cout << length << ", " << width << endl;
}
};
int main()
{
MyClass mc1(10, 10), mc2(20, 20), mc3(30,30);
mc1.show();
mc2.show();
mc3.show();
ofstream myOut("D:\\test1.txt", ios_base::binary | ios_base::out);
myOut.write((char*)&mc1, sizeof(mc1));
myOut.write((char*)&mc2, sizeof(mc2));
myOut.close();
ifstream myIn("D:\\test1.txt", ios_base::binary | ios_base::in);
myIn.seekg(sizeof(MyClass));
myIn.read((char*)&mc3, sizeof(mc3));
myIn.close();
mc3.show();
return 0;
}
错误处理函数
错误处理函数的主要作用是得到流对象当前的状态。
eof(),如果输入流结束,到文件尾,则返回true。
bad(),如果出现严重错误,不可恢复的错误,则返回true。
fail(),如果某种操作失败,则返回true。
good(),以上三种错误均未发生,则返回true。表示流对象状态正常。
clear(),清除所有错误状态。
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
int n;
char c;
cin >> n;
cout << "n: " << n << endl;
cout << "cin.good(): " << cin.good() << " cin.bad(): " << cin.bad() << " cin.fail(): " << cin.fail() << endl;
// 清除错误状态奇
cin.clear();
cout << "cin.good(): " << cin.good() << " cin.bad(): " << cin.bad() << " cin.fail(): " << cin.fail() << endl;
cin >> c;
cout << "c: " << c << endl;
// eof()判断文件是否读完了
ifstream myIn("D:\\test.txt");
while (!myIn.eof())
{
myIn.get(c);
cout << c ;
}
myIn.close();
return 0;
}
输入输出文件流
fstream 同时具有输入和输出的功能。
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
fstream myInOut("D:\\d.txt", ios::in | ios::out);
// 定位读指针到文件末尾
myInOut.seekg(0, ios::end);
cout << "myInOut.tellg(): " << myInOut.tellg() << " myInOut.tellp(): " << myInOut.tellp() << endl;
// 获取文件长度
streampos len = myInOut.tellg();
cout << "len: " << len << endl;
// 动态分配空间用于存储文件内容
char* data = new char[len];
// 移动读指针到文件开头位置
myInOut.seekg(0, ios::beg);
myInOut.read(data, len);
// 移动写指针到文件末尾
myInOut.seekp(0, ios::end);
// 写入文件
myInOut.write(data, len);
delete[]data;
myInOut.close();
return 0;
}