个人见解 :对于输入输出我们在实际项目中并不会使用太多,所以没有必要死记硬背,只需要了解,知道有这么个东西,将来做项目时候随用随查就行
要了解什么是流我们首先要了解缓冲技术
缓冲(buffer):
从键盘中每读写一个字符都需要大量的硬件活动,这样,向磁盘读写数据时候就会花费大量的时间,为了避免频繁的读写数据,因此提供了缓冲技术.当从键盘中输入字符的时候,数据不会立马写进磁盘,而是通过流的操作读进缓冲区,之到缓冲区充满,才一次性入磁盘。
缓冲区是内存中的一块区域,由于内存的读写速度比硬盘快,因此当大量数据储存在内存中无疑会提高对数据的访问速度.当缓冲区被填满的时,数据会一次性写进硬盘,然后缓冲区清空,并为下次数据的到来做准备。
在c++中,当输出时遇到endl的时候会换行加清空缓冲区,将数据输入到屏幕上,而在输入的时候当用户按下Enter的时候会清空缓冲区,将数据写进磁盘
c++中的流:
streambuf类管理着缓冲区,它的成员函数提供填充缓冲区,访问缓冲区,刷新缓冲区,和管理缓冲区内存的功能
ios类是输入和输出流类中的基类,它有一个指向streambuf对象的指针成员.
istream派生于ios类,提供标准输入方法,ostream派生于ios类,提供标准输入方法
iostream派生于istream和ostream
fstream类提供对文件的输入和输出操作
标准输入输出对象:
类iostream继承与标准输入流istream和标准输出流ostream,所以它同时继承istream类的cin对象,以及ostream的cout对象,除此之外还继承了cerr对象以及clog对象
1.cerr对象用于向标准输出设备(屏幕)发送非缓冲信息,由于是非缓冲的,因此数据不会等到缓冲区买了才输出到屏幕
2.clog对象用于想输出设备(屏幕)输出缓冲消息,这种输出一般重定向到日志文件
当我们使用iostream的cout对象输出数据时,cout对象将在输出之前保存有关数据,
如 cout<<”hello world!”;
通过streambuf对象将字符串“hello world”放置在缓冲区,ostream类的operator<<函数(函数重载)调用cout对象将字符串按流的方式输出到屏幕上
上面所说的ostream类的operaotr<<函数其实是对操作符”<<”进行了重载,cout对象可以输出多种类型的数据,则说明operator<<也被重载了多次
如 int,unsinged int,short,unsigned short,long,unsigned long,float,double,long double,char,unsigned char.
operator<<函数会将各种类型的数值转化为字符,然后以流的方式输出在屏幕上。
由于c++用指向字符串位置的指针来表示字符串,如 char*ch=“hello world”;
因此ostream类重载了char型指针类型的插入运算符<<,如下:
ostream&operator<<(void*); //用于输出任何类型的地址 如int a=45;cout<<&a;
ostream&operator<<(const char*);
ostream&operator<<(const signed char*);
ostream&operator<<(const unsigned char*);
从上面函数的返回值ostream&可以看出,由于返回的是ostream类的对象,因此可以使用长式进行输出,如cout<<”hello”<<”world”;
*如前面所说当输入endl的时候,程序会执行换行的同时清空缓冲区(调用flush()函数).
如cout<<”hello world”<<endl; === cout<<”hello world”<<”\n”<<flush;
有关输出的相关函数
ostream提供了put()和write()函数
函数原型:
ostream&put(char);
ostream&write(string,length);
put()函数用于输出单个字符,write()用于输出字符串 //cout.put(‘a’) cout.write(string,length)
由于put()只接受char类型的参数,当试图输出一个整型时如put(35),则会将35视为ASCII码输出则为’#’
write()函数需要两个参数,第一个个需要输出的字符串名,第二个为需要输出多少个字符
ostream成员函数
设置输出的字段宽度(只影响将要显示的对象,然后自动恢复默认值)
int width();
int width(int);
设置填充字段(默认为空格)
cout.fill(char) //效果一直有效
设置浮点数的精度(默认为6位)
cout.precision(int); //效果会一直有效
设置标志
由于ios类派生于ios_base类,又因iostream间接继承ios,所以iostream间接继承了ios_base类的setf()方法,setf()方法用来设置几种输出格式。
所谓的标志都是枚举型常量,它用来设置ios标志,这个ios标志是ios类从iso_base类中继承而来的受保护数据成员,该成员用来记录格式标志,我们可以通过设置该标志来控制各种格式的输入输出效果。这些用来设置标志的枚举常量与ios_base类的受保护的数据成员的二进制数字一一对应。如ios::internal在vc6中为
boolalpha fixed scientific hex oct dec internal right left showpos showpoint showbase uppercase unitbuf skipws
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
与二进制数字000000100000000对应
boolalpha 输入和输出使用bool值(TRUE OR FALSE)
showbase 向十六进制数添加0x,向8进制数中添加0
showpoint 显示末尾的小数点
uppercase 用大写字母表示十六进制,用科学技术法表示10进制
showpos 正数前面加+
dec 输出十进制
oct 输出八进制
hex 输出十六进制
fixed 用十进制表示法表示浮点数
scientific 用科学计数法表示浮点数
skipws 跳过输入流中的空白字符
unitbuf 每次执行输出操作后均会清空缓冲区
left 按指定的宽度向左对齐
internal 符号左对齐,值右对齐
right 按指定的宽度向右对齐
setf()函数原型:
fmtflags setf(fmtflags);
fmtflags setf(fmtflags,fmtflags);//第一个参数指定要打开的标志位,第二个参数则指定要清除的标志位
为了避免同时开启了多个标志位而导致编译器不知道应用哪个所以一般使用第二个函数原型在设置的时候现将有冲突的标志位清除
ios::basefild -> dec,oct,hex
ios::floatfield -> fixed,scientific
ios::adjustfield -> left,right,internal //如cout.setf(ios::internal,ios::adjustfield);
unset()函数用来实现标记位的清空。
对于上述的格式化操作,在iomanip头文件中也提供相似的函数
标准输入流
operator>>函数的返回值为istream&,因此也可以实现长式。
cin把空格当做分隔符来看待,当它看到一个空格或者换行符时,它就认为当前的输入已经完成,因此它会自动在空格处加一个空字符当做字符串的结果标志,如
cin>>str; //当输入hello world 时,在调用cout<<str;时候只输出hello。
输入函数
get()函数和read()函数
int get();
istream &get(char &ch);
istream &get(char *buffer,streamsize num)
istream &get(char *buffer,streamsize num,char delim);
istream &get(streambuf &buffer);
istream &get(streambuf &buffer,char delim);
cin.ignore() //会丢弃放在缓冲区中的第一个字符
cin.ignore(1024,’\n’);//清空整个缓冲区
或者使用cin.ignore(std::numeric_limits<std::streamsize>::max(),’\n’);
std::numberic_limits<std::streamsize>::max();返回缓冲区的最大容量 在头<limits>中声明
read()函数
istream&read(char *buffer,streamsize num);
getline()函数 //会自动抛弃掉换行符
istream&getline(char *bufffer,streamsize num);
istream&getline(char *buffer,streamsize num,char delim);
gcount()函数
gcount()函数返回get(),getline(),read(),ignore9)方法所读取的字符数
peek函数
int peek() //读取输入流中的下一个字符
putback函数
istream &普通把车开(char ch) //讲一个字符插入(替换)到输入流的字符串中
文件的输入和输出
要让程序中的数据输出文件,需要以下5个步骤 从文件中读取数据,也需要5个步骤
1.包含fstream头文件 1.包含fstream头文件
2.建立ofstream对象 2.建立ifstream对象
ofstream ocout; ifstream icin;
3.将对象与文件关联 3.将对象与文件关联
ocout.open(“demo.txt”); icin.open(“demo.txt”);
4.该对象可以看做cout对象, 4.该对象可以看做cin对象
ocout<<”abcdefg”; icin>>temp;
5.关闭文件的连接 5.关闭与文件的连接
ocout.close(); icin.close();
打开文件的方式
ios::in 打开文件进行读操作,既读取文件中的数据
ios::out 打开文件进行写操作,既输出数据到文件中
ios::ate 打开文件时文件指针指向文件末尾,但是你可以在文件中的任何地方写数据. //at end
ios::app 打开文件不会清空数据,文件指针始终在文件尾,因此只能在文件尾写数据 //append
ios::trunc 默认,若打开文件已存在,则清空文件的内容 //truncate
ios::nocreate 若打开文件不存在则不建立,返回打开失败信息
ios::noreplace 打开文件时不能覆盖,若文件存在则返回打开失败信息.
ios::binary 打开文件为二进制文件,否则为文本文件
检查文件是否打开
当iostream对象遇到文件结束符号EOF时,函数eof()返回真
当试图进行非法操作时,函数bad返回真
当函数bad()为真,或者流操作失败时,fail返回真
当eof(),bad(),fail()均返回为假时,good()函数返回真
在新版本的c++中提供了一种更好的检测文件是否打开的方法,既使用is_open()方法 //if(fin.is_open());
*如何连换行符也也一起读取,使用getline()函数的第三个参数就可以实现,将第三个参数换位”\0”.
指定读取文件中的数据
假如我们不想全部读入文件中的数据,而是只读取其中的某项数据,南无fstream类的seekg()成员函数可以为我们达到目的,
istream &seekg(pos_type position); //将指针定位到离文件开头position个字节处
istream &seekg(off_type offset,ios::seekdir orgin); //将指针定位到距第2个参数指定的位置offset个字符处
ios::seekdir orgin的值:
iso::beg //相对于文件开头的偏移量
ios::cur //相对于当前位置的偏移量
ios::end //相对于文件结尾的偏移量
输出数据到文件指定位置处
假如我们想要在文件指定位置处输出数据,南无fstream类的seekp()成员函数可以为我们达到目的,
ostream &seekp(off_type offset,ios::seekdir origin);
ostream &seekp(pos_type position);
ofstream类,ifstream类,fstream类的默认打开方式
ofstream类在默认情况下开启iso:trunc和ios::out标志位,因此既可以输出也可以覆盖原始数据
ifstream 类默认情况下开始ios::in标志位
fstream默认情况下不提供模式,这样创建时必须为它提供模式,如果不提供则将根据后面的操作确定它的模式
*clear()函数用于重置流状态,当程序遇到EOF后,会自动设置eofbit标志,该标志用来说明此文件已经被操作过,并且进制对该文件在进行读写操作,因此我们要重现设置流状态,并且开始eofbit标志,以保证我们可以再次访问该文件.
临时文件
临时文件从字面上看就是临时创建的文件,因此这种文件必须受程序控制,而且存在是短暂的。创建一个链式文件,对它进行复制或者删除都很简单,但对齐进行命名却有些麻烦,因为我们知道文件名是独一无二的,那么如何才能使其与本机上存在的文件名不相重复呢,头文件<cstdio>中声明的tmpname()函数可以帮助我们解决这个问题
char * tmpname (char *name);//创建一个独特的文件名并保存在name中,tmpname()最多可以调用TMP_MAX指定的次数.
TMP_MAX 该常量表示tmpname()最多可以调用的次数,它与另一个常量L_tmpname 在头文件cstdio中被定义,常量L_tmpname的值是临时文件名的字符数目
C++的sstream标准库介绍
我们看一下C++风格的串流控制,C++引入了ostringstream、istringstream、stringstream这三个类,要使用他们创建对象就必须包含sstream.h头文件。
istringstream类用于执行C++风格的串流的输入操作。
ostringstream类用于执行C风格的串流的输出操作。
stringstream类同时可以支持C风格的串流的输入输出操作。