1、相关类、对象
(1)输入输出流相关的类
streambuf类:管理输入/输出缓冲区的内存;
ios类:基于ios_base类,描述一般的流属性,包括一个指向streambuf的指针(如字段宽度,显示基数等);
ostream类:由ios类派生而来,提供输出方法;
istream类:由ios类派生而来,提供输入方法;
iostream类:继承输入、输出方法。
(2)iostream会使用宏定义定义8种,流对象分别面向窄、宽字符流。
cin是输入流,cout对应输出流,cerr对应标准错误流,无缓存显示错误信息,clog对应标准错误流,有缓存显示错误信息
默认情况下,以上对象关联到标准的输入输出设备,也就是键盘和屏幕
(3)重定向
在命令行运行模式下可以进行标准输入、输出连接设备的重定向,输入重定向(<)、输出重定向(>)。有些操作系统也允许对错误流的输出重定向。
在编译器中,我们执行重定向操作使用ios::rdbuf()方法。对于这个方法,如果不传参数,那么直接返回流对象的buffer指针。如果传递了某个流对象的buffer指针,那么将当前的流对象绑定到那个传递过来的流对象的buffer上。
// cout 重定向到文件
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
fstream file; // 定义fstream对象
file.open("D:\cout.txt", ios::out); // 打开文件,并绑定到ios::out对象
string line;
// 先获取cout、cin的buffer指针
streambuf *stream_buffer_cout = cout.rdbuf();
streambuf *stream_buffer_cin = cin.rdbuf();
// 获取文件的buffer指针
streambuf *stream_buffer_file = file.rdbuf();
// cout重定向到文件
cout.rdbuf(stream_buffer_file);
cout << "This line written to file" << endl;
// cout重定向到cout,即输出到屏幕
cout.rdbuf(stream_buffer_cout);
cout << "This line is written to screen" << endl;
file.close(); // 关闭文件
return 0;
}
这是由于程序并不是直接对文件或收入输出设备操作的,而是从缓存中读取、存入,只要改变了流对应的缓存的指向,就可以实现重定向。
2使用cout进行输出
cout可以将字符,字符串,整形,浮点型都转化为字符字节输出以文本的形式表示,并通过控制符或ios_base::setf();方法修改输出的属性。(不面向string类型,string使用的是cin的友元函数)
2.1重载<<运算符
cout重载了<<运算符,可以实现以上基本类型的输入输出,同时还可以实现对字符串指针所指空间内容的输出,并返回cout对象。
(1)指向字符串存储位置的指针,显示字符串,要输出地址需要转换为(void*)
(2)其他类型的指针会被转化为(void*)输出地址;
(3)字符串以结束的空字符为标志结束输出。
2.2其他类方法
某些老版本的C++会用int值来表示字符常量,为了能够显示是字符常量,输出类提供类方法put();
cout.put('a');
cout.put(14);//输出该ASCII码对应的字符
还有某些时候希望输出字符串的一部分,可以用write()类方法
cout.write(char* sptr,int len);
write()类方法不通过检测空字符结束输出,而是逐个字节显示对应的ASCII码。
这两个类方法,都会返回类对象也就是cout所以可拼接使用。
2.3刷新缓冲区
意思就是想缓冲区的内容送达设备或者文件中,有三种方法可以刷新
1、缓冲区填满,512个字节为单位一次性写入磁盘
2、利用控制字符flush或endl强制刷新,后者还有换行的作用(对屏幕意外的设备,或者文件是否起作用)
cout<<flush<<endl;
3、屏幕输出时,不必等待缓冲区满,输入即将发生会自动刷新
2.4输出格式化
这个前面复习过,可以用width()方法函数设置字段宽度
pricision()方法函数设置浮点数进度,fill()方法函数设置填充内容
对应的控制字符
setpricision(),setw(),setfill()
控制字符:
showpoint,showbase,boolalpha,showpose,uppercase
dec,hex,oct(basefield),left,right,internal(adjustfield),fixed,scitific(floatfield);
3使用cin进行输入
cin将标准输入翻译为字节流,解释输入的字符序列的方式,取决于用于存储输入的内存单元的格式。
cin>>value_holder;
value_holder的类型可以为基础类型,还可以是引用、解引用的指针、结构体或类对象。
函数原型为:
istream& operator>>(T&);
格式输入函数,将输入数据转化为目标类型。
3.1cin格式化
和cout对应的格式化控制符
dec、hex、oct(只对存储空间对应为整数时有效)
认为输入流中的输入的是整数的相应进制数,然后转化为对应的十进制数存储。
和cout相似,要特别考虑字符串的输入的情况,
cin针对以下字符指针重载了>>抽取指针,读入从非空白字符开始,到第一个与目标类型不匹配的内容。
signed char*
char*
unsigned char*
在字符尾会自动填充'\0'。
关于cin如何检查输入
抽取字符会跳过空白(换行符、制表符、空格),从第一个非空开始读取,到第一个不匹配的内容结束。
如果第一个非空字符不是目标类型,cin将返回false,也不会修改目标内存的内容。
3.2流状态(iostate类型)
流状态由3个ios_base元素构成:eofbit、failbit、badbit。当读取带文件尾时,设置为eofbit为1;当没有读取到目标格式的字节,或者I/O输入输出有错时,状态位设为failbit;当出现其他无法检测的流时,状态位设为badbit。
如果一切正常,就是goodbit所有位都为0。
相关的常用方法函数有:clear(iostate s),exception(iostate s),fail(),eof();bad();
istream对象可以根据流状态,装换为bool类型,如果流状态位非0将转换为false类型。
3.3其他类方法
由于cin会跳过空字符(空格、制表、回车),所以有get()方法用于字符读取;
另外,由于cin遇到空字符会停止,不能读取整行,所以有get()、getline()方法用于字符行的读取。
1、单字符的输入
有两种形式
istream& get(char& ch);
int get(void);
这两个成员函数,一个返回调用对象的引用,一个返回字符ASCII码对应的值。注意第二个返回的是整数。
所以在遇到文件尾时,第一个会将cin的流状态设为eofbit=1使得cin检测为false;
而第二个函数会返回,符号常量EOF。
这两个成员函数有三方面的不同:1字符读取:一个参数复制,一个返回;2返回:一个返回流对象引用,一个返回int;3遇到文件尾:一个设置流状态标志位,一个返回EOF符号常量。
两个有个相同的特点,就是相对于<<抽取运算符,两个成员方法都不会进行格式转换。
2、字符串的行输入
istream& get(char* ch,int len,char ch);//不读取换行符
istream& getline(char* ch,int len,char ch);//读取并丢弃换行符
istream& ignore(int len,char ch);
三个参数的含义:用于存放存储字符串的内存的起始地址,第二个参数说明从流中读取的最多的字节数(大一,最后要不一个空字符),第三个是分界符标志位(默认为换行符'\n')。
前两个用于读取字符并存入到相应的位置,最后一个方法是读取和丢弃。
istream& ignore(int = 1,int EOF);//前一个默认丢弃下一个字符,后一个默认到文件为结束,满足其中一个就可以。
处理string时,可以用string类的友元函数,getline(istream& cin,string& str);
template<class _Elem,
class _Traits,
class _Alloc> inline
basic_istream<_Elem, _Traits>& getline(
basic_istream<_Elem, _Traits>& _Istr,
basic_string<_Elem, _Traits, _Alloc>& _Str,
const _Elem _Delim)
{ // get characters into string, discard delimiter
return (getline(_STD move(_Istr), _Str, _Delim));
}
另外上面两个类方法如果读取了空行,会将流状态中failbit置为1。
getline类方法如果没有读取到最后一个字符,行中还有其他字符,也会将failbit置为1。
其他成员方法:
read(char* str,int len);和write(char* str,int len);对应读取对应长度的字符,最后不添加空值字符。
char peek();返回下一个输入字符,不抽取;
int gcount();返回上一个非格式化抽取的字符数;
istream& putback(char);在输入流中插入字符,下一次读取。
4 文件的输入输出(重点)
对应的头文件fstream
计算机对文件的操作分为三个部分:将程序和文件关联的途径,让程序读取文件内容的途径以及让程序创建和写入文件的途径。
按照代码可以分为:建立ifstream,ofstream流对象;关联到文件,确定打开文件模式;使用继承的iostream类方法进行文件写入和读取。
ifstream fin;
fin.open("text.txt",ios_base::in);
fin>>ch;
ifstream fin("text.txt",ios_base::in);
fin>>ch;
ofstream fout("text.txt",ios_base::out);//等价为ios_base::out|ios_base::trunc
fout<<ch;
第二个参数为文件模式,可以省略,默认参数为后面的值,out等价于写入并截短为零。
此外和iostream一样,在文件和程序之间的流运用缓冲区,实现速率匹配。
4.1是否成功打开
从ios_base中继承流状态成员,failbit/eofbit/badbit。
如果打开不存在的文件读取的话会造成failbit,相应的fin为false。
不过这样检测不完全,如果文件模式不正确,不能检测出
常用以下模式
#include<cstdlib>
fin.open();
if(!fin.is_open()){
//如果没有成功打开
cerr<<"Could not open"<<char*<<endl;
exit(EXIT_FAILURE);
}
4.2打开的模式
文件模式对应的是openmode类型、
ios_base::openmode mode = ios_base::in;
常见的c++文件打开模式
例如在文件尾追加数据fout.open("text.txt",ios_base::out|ios_base::app);
4.3存入的方式:二进制存储
将数据存储在文件中可以存储为文本格式或二进制格式。