输入输出流对象
输入的方式有很多,但是最常用的方式是通过文件进行输入;同理,输出流通常也就输出到文件中进行保存。
c++的输入与输出包括:
1. 对系统指定的标准设备的输入-----------标准i/o:键盘与显示器
2. 以外存磁盘文件为对象的输入和输出--------文件I/O:文件 。操作系统中将设备也当做文件,所以这个方式也可以对设备进行操作。
3. 对内存中指定的空间进行的输入和输出---------串I/O:计算机中运行的两个程序之间,内存块之间通信,不需要外部介质,直接进行通信。
输入输出“流”:若干个字节组成的字节序列。流表示信息从源到目的端的流动。
为了实现数据的有效流动,c++中有很多类库,调用不同的类去实现不同的功能。顶层类为ios,派生出istream,ostream,这两个类派生出iostream。等等。
与iostream类库有关的头文件:
头文件是程序与类库的接口,iostream类库的接口分别由不同的头文件来实现。
常用的头文件:
iostream:包含对输入输出流进行操作的基本信息
fstream:用于用户管理的文件的I/O
strstream:用于字符串流I/O
stdiostream :用于混合使用c和c++的I/O机制
iomanip:使用格式化I/O时应包含此头文件
iostream头文件中对<<和>>进行了重载,用于标准类型数据的输入和输出。在istream和ostream类中对位移运算符进行重载,定义为ostream和istream
类的成员函数,而不是我们自己定义重载时只能是友元函数,比如:
ostream operator<<(int)
ostream operator<<(float)
在iostream头文件中定义了4个重要流对象,可以看做系统自动提供的:
cin:从标准输入设备(键盘)输入到内存的数据流对象
cout:从内存输出到标准输出设备(显示器)的数据流对象
cerr和clog--------向输出设备(显示器)输出出错信息
理解:数据流对应缓冲区
在内存中为每一个数据流开辟一个内存缓冲区:
在包含程序数据区的内存中,针对要输入和输出的每一个文件会专门开辟一段输出文件缓冲区和输入文件缓冲区。也就是说程序数据区和文件或者设备之间还有一段缓冲区。
在内存中为每一个数据流开辟一个内存缓冲区。
缓冲区用来存放流中的数据,缓冲区中的数据就是流。
c++中输入输出流被定义为类,c++中的I/O库中的类被称为流类。
例子:
for(int i=0;i<5;i++)
{
cin>>n[i];
cout<<n[i]<<endl;
}
对于上面的程序来说,如果输入为:
1 2 3 4 5
那么输出的结果就是
1
2
3
4
5
之所以会这样是因为,一开始输入的数据全都存储在输入缓冲区,当用cin读取的时候因为它每次只读取了一个,所以每次都只能输出一个;
比如说第一次的时候cin读取了1到n[0]中,然后输出n[0];然后用cin读取了缓冲区中的下一个数2,所以输出为2;以此类推,也就是说缓冲区中的
数据是第一个少一个的!!因为缓冲区中尚有数据,便不再停下来等待输入.....
标准输出流:
cout(console output)对象:标准输出流,是流向标准输出设备的数据
ostream类定义了3个输入流对象:cout cerr clog
cout流在内存中开辟了一个缓冲区,用来存放流中的数据,当向cout流插入一个endl时,立即输出流中的所有数据,然后插入一个换行符,并刷新流(清空缓冲区)。
cout.flush()输出流中所有数据,刷新缓冲区;
cerr流对象:
cerr对象是标准错误流,被指定为与显示器关联;
cerr的作用是向标准错误设备输出又出错信息;
cerr与标准输出流cout的作用和用法差不多,但是
cout流通常是传送到显示器输出,但也可以被重定向输出到磁盘文件;
cerr流中的信息只能在显示器输出。(程序运行过程中限定只能输出到显示器的信息就能用cerr,cout有可能重定向输出到别的地方去)
clog流对象:也是标准错误流。console log
作用和cerr相同,都是在终端显示器上显示出错的信息。
区别:
cerr不经过缓冲区,直接向显示器上输出有关信息;
clog中的信息存放在缓冲区中,缓冲区满后或遇到end时向显示器输出;
使用控制符控制输出格式:
setfill(c) 设置填充字符c,c可以是字符常量或者字符变量
用strlen求字符串长度是不算“\0”的,用sizeof求字符串长度算‘\0’。
endl是一个ostream操纵符,它把一个换行符插入到输出流中,然后再刷新ostream缓冲区。
cout显示内容的时候会先将要显示内容存放在缓冲区中,等到刷新的时候才将内容在屏幕上显示。
有许多种情况可以引起缓冲区被刷新(即清空)。也就是将缓冲区写到标准输出上,强迫缓冲区的内容输出:
1. 缓冲区可能会满,这种情况下,它必须被刷新,以便读取后面的值;
2. 通过显示地使用flush,ends,或endl操作符来刷新缓冲区;
3. unitbuf,一个内部的流状态变量,若它被设置,则每次输出操作后都会清空缓冲区;
4. ostream对象可以捆绑到istream上,在这种情况下,当istream从输入流读取数据时,ostream的缓冲区就会被刷新。cout被预定义为“捆绑”在cin上:
一个ostream对象一次只能捆绑到一个istream对象上,为了打破现有的捆绑,可以传递一个实参0;
5. 程序结束
iomanip主要是对cin和cout之类的一些操纵运算子,比如setfill,setw,setbase,setprecision等等。它是I/O流控制头文件,就像c里面的格式化输出一样。下面是一些常用的控制函数。
在C++中,setw(int n)用来控制输出间隔。也表示后面的字符的字符宽度,也就是加上这个字符一共占用n个位置。
例如:
cout<<'s'<<setw(8)<<'a'<<endl;
则在屏幕显示
s a
//s与a之间有7个空格,setw()只对其后面紧跟的输出产生作用,如上例中,表示'a'共占8个位置,不足的用空格填充。若输入的内容超过setw()设置的长度,则按实际长度输出。
setw()默认填充的内容为空格,可以setfill()配合使用设置其他字符填充。
如
cout<<setfill('*')<<setw(5)<<'a'<<endl;
则输出:
****a //4个*和字符a共占5个位置。
除了上面的方式可以实现格式化输出之外,因为cout是流对象,所以一定有自己的成员函数,因此可以通过用流对象的成员函数控制输出格式。通过调用流对象cout中用于控制输出格式的成员函数来控制输出格式:比如说precision(n),width(n),fill(c)setf,以及unsetf等。
输出流对象的成员函数:
ostream类中专用关于输出单个字符的成员函数 ostream& put(char c)
比如:
cout.put('a').put(71).put(79)
标准输入流:
从标准输入设备(键盘)流向程序的数据。
cin是istream类的对象,从标准输入设备(键盘)获取数据。
程序中的变量通过流提取符“>>”从cin流中提取数据:
流提取符从流中提取数据时,通常跳过流中的空格、tab键、换行符等空白字符。如果出现空白字符,整个一次接受输入的过程就结束了。除非又出现了cin,这样的话缓冲区中空白字符后面的值就可以被提取了;
只有输入完数据在按回车键后,该行数据才被送入到键盘缓冲区,形成输入流,提取运算符才能从中提取数据。
程序将从键盘缓冲区中连续地获得数据:
当遇到无效字符或文件结束符(^Z)时,cin无法正常提取数据,处于出错状态,返回0值(false):(其中^Z就是ctrl+z)
所以在程序中通常用while(cin>>grade)来判断是否输入了一个非法的数据。
用于字符输入的流成员函数:
1.不带参数的get函数-----------cin.get()
与c中的getchar()相同;
从输入流中提取一个字符,返回读入的字符,比如c=cin.get();
遇到输入流中的文件结束符,则返回EOF(END OF FILE).EOF对应一个常量,数值为-1. 所以通常有while((c=cin.get())!=EOF)进行判断。
2.有一个参数的get函数----cin.get(c)
从输入流中读取一个字符,赋给字符变量c;
读取成员返回真,失败(遇到文件结束符)返回0假。所以经常有while(cin.get(c))进行判断。
3. 有三个参数的get函数-----cin.get(字符数组或指针(相当于字符串),n,终止字符)
从输入流中读取n-1个字符,赋给指定的字符数组;这里之所以为n是因为有一个'\0‘,所以是n个字节表示的字符串。’
如果在读取n-1个字符之前遇到指定的终止字符,则提前结束读取;
读取成功返回真,失败返回假0. 如果输入的字符就是一个终止字符,那么就会返回0.
对于cin.get()这个函数来说是可以识别空白字符的,这是和单独使用cin的差别,也就是说遇到空白字符这个函数并不会停止这一次的提取,而是将这个空白字符也提取出来。如果cin的话就会忽略这个空白字符,然后在下一次的cin的时候才会提取空白字符后面的字符。
用于输入一行字符的流成员函数-------getline函数:
getline的作用是从输入流中读取一行字符:
istream& getline(char* buffer,streamsize num)
istream& getline(char* buffer,streamsize num, char delim)
getline()函数用于输入流,读取字符到buffer中,直到:
1. num-1个字符已经读入
2. 碰到一个换行标志
3. 碰到一个EOF
4. 读到字符delim
getline()函数遇到空白字符不结束!!!
判断输入(文件)是否结束---------eof函数:专门寻找文件的结束符
eof表示“文件结束”。
从输入流读取数据:
如果到达文件末尾(遇文件结束符),eof函数值为非零值(表示真),否则为0(假)。
比如:
while(!cin.eof())
{
if((c=cin.get())!=" ")
cout.put(c);
}
上面这段代码可以将文件中的除了空格以外的字符都读出来。
上面的函数中,peek和putback都是对缓冲区进行操作,输入流就相当于缓冲区。