面向对象的标准库
实际的程序不仅限于对控制窗口的IO,通常还需要读或写已命名的文件。此外,程序还应该能够方便地使用IO操作格式化内存中的数据,从而避免读写磁盘或其他设备的复杂性和运行代价。应用程序还需要支持宽字符语言的读写。
从概念上看,无论是设备的类型还是字符的大小,都不影响需要执行的IO操作。要同时支持不同的设备和不同大小的字符流,标准库使用了继承来定义一组面向对象的类。一般而言,通过继承关联起来的类型都共享公共的接口。如果两个类型存在继承关系,则可以说一个类(派生类)“继承”了其父类(基类)的行为——接口。
IO类型在三个独立的头文件中定义:iostream定义读写控制窗口的类型,fstream定义读写已命名文件的类型,而sstream定义的类型则用于读写存储在内存中的string对象。在fstream和sstream里定义的每种类型都是从iostream头文件里定义的相关类型派生而来。
头文件iostream中包含的类型:istream 从流中读取,ostream写入到流中去,iostream对流进行读写,从istream和ostream派生而来。
头文件fstream中包含的类型:ifstream从文件中读取,由istream派生而来;ofstream写到文件中去,由ostream派生而来;fstream读写文件,由iostream派生而来。
头文件sstream中包含的类型:istringstream从string对象中读取,由istream派生而来;
ostringstream写到string对象中去,由ostream派生而来;
stringstream对string对象进行读写,由iostream派生而来。
由于ifstream和istringstream类型继承自istream类,故读istream对象的程序也可用于读文件(ifstream)或者string对象(istringstream)。类似地,提供输出功能的程序同样可用于ofstream或ostringstream取代ostream类型实现。除istream和ostream类型之外,iostream头文件还定义了iostream类型。iostream类型继承自istream和ostream。这意味着iostream对象共享了他的两个父类的接口。iostream类型在同一个输入流上实现输入和输出操作。
对IO类使用继承的另外一个含义:如果函数有基类类型的引用形参时,可以给函数传递其派生类型的对象。这样就可以编写一个函数,而将它应用到三种类型的流上:控制台、磁盘文件或者字符串流。
IO对象不可以复制或赋值,这个要求有两层含义:1、只有支持复制的元素类型可以存储在vector或者其他容器类型里,因此流对象是不能存储在vector(或其他)容器中的(即不存在存储流对象的vector或者其他容器)。2、形参或返回类型也不能为流类型。如果需要传递或返回IO对象,则必须传递或返回该对象的指针或引用。
一般情况下,如果要传递IO对象以便对它进行读写,可用非const引用的方式传递这个流对象。对IO对象的读写绘改变它的状态,因此引用必须是非const的。
IO类型在三个独立的头文件中定义:iostream定义读写控制窗口的类型,fstream定义读写已命名文件的类型,sstream所定义的类型用于读写存储在内存中的string对象。
头文件 | 类型 |
iostream | istream 从流中读取 |
fstream | ifstream 从文件中读取,由istream派生而来 |
sstream | istringstream从string对象中读取,由istream派生而来 stringstream 对string对象进行读写, 由iostream派生而来 |
1. 国际字符的支持
到目前为止,所描述的流类读写的是由char类型组成的流。此外,标准库还定义了一组相关的类型,支持wchar_t类型。每个类都加上“w”前缀,以此与char类型的版本区分开来。于是,wostream、wistream和wiostream类型从控制窗口读写wchar_t数据。相应的文件输入输出类是wifstream、wofstream和wfstream。而wchar_t版本的string输入/输出流则是wistringstream、wostringstream和wstirngstream。标准库还定义了从标准输入输出读写宽字符的对象。这些对象加上"w"前缀,以此与char类型的版本区分:wchar_t类型的标准输入对象是wcin;标准输出是wcout;而标准错误则是wcerr。
每个IO头文件都定义了char和wchar_t类型的类和标准输入/输出对象。基于流的wchar_t类型的类和对象在iostream中定义,宽字符文件流类型在fsteam中定义,而宽字符stringstream则在sstream头文件中定义。
2. IO标准库不可复制或赋值
这里先不说为什么标准IO库不允许做复制或赋值操作。以后将会查资料补上来。
一、只有支持复制的元素类型可以存储在Vector或其他容器类型里。由于流对象不能复制,因此不能存储在vector(或其他)容器中;
二、形参或返回类型也不能为流类型。若需要传递或返回IO对象,则必须传递或返回指向该对象的指针或引用。一般情况下,如果要传递IO对象以便对它进行读写,可用非const引用的方式传递这个流对象。对IO对象的读写会改变它的状态,因此引用必须是非const的。
3.条件状态
IO标准库管理一系列条件状态成员,用来标记给定IO对象是否处于可用状态,或者碰到了哪种特定的错误。标准库定义的一组函数和标记,提供访问和操纵流状态的手段。
strm::iostate 机器相关的整型名,由各个iostream类定义,用于定义条件状态
strm::badbit strm::iostate类型的值,用于指出被破坏的流
strm::failbit strm::iostate类型的值,用于指出失败的IO操作
strm::eofbit strm::iostate类型的值,用于指出流已经到达文件结束符
s.eof() 如果设置了流s的eofbit值,则该函数返回true
s.fail() 如果设置了流s的failbit值,则该函数返回true
s.bad() 如果设置了流s的badbit值,则该函数返回true
s.good() 如果流s处于有效状态,则该函数返回true
s.clear() 将流s中的所有状态值都重设为有效状态
s.clear(flag) 将流s中的某个指定条件状态设置为有效。flag的类型是strm::iostate
s.setstate(flag) 给流s添加指定条件。flag的类型是strm::iostate
s.rdstate() 返回流s的当前条件,返回值类型为strm::iostate
流必须处于无错误状态,才能用于输入或输出。检测流是否可用的最简单的方法是检查其真值:
if (cin) // if 语句直接检查流的状态
while (cin >> word) //while语句则检测条件表达式返回的流的状态,若成功输入,则条件检测为真
4. 缓冲区管理
每个IO对象管理一个缓冲区,用于存储程序读写的数据。如有下面的语句:
os << " please enter a value:";
系统将字符串字面值存储在流os关联的缓冲区中。下面几种情况将导致缓冲区的内容被刷新,即写入到真实的输出设备或者文件:
(1)程序正常结束。作为main返回工作的一部分,将清空所有输出缓冲区;
(2)在一些不确定的时候,缓冲区可能已经满了,在这种情况下,缓冲区将会在写下一个值之前刷新;
(3)用操纵符显式地刷新缓冲区,例如行结束符endl;
(4)在每次输出操作执行完后,用unitbuf操纵符设置流的内部状态,从而清空缓冲区;
(5)可将输出流与输入流关联起来。在这种情况下,在读输入流时将刷新其相关的输出缓冲区。
例子:
例子:
●创建并向文件写入信息:
方式一:
#include <fstream.h>
#include <iomanip.h>
void main()
{
ofstream f1("a.txt");
if (!f1)
{
return;
}
f1<<"姓名:"<<"袁孙良"<<endl;
f1<<"性别:"<<"男"<<endl;
f1.close();
}
方式二:
#include <fstream.h>
void main()
{
ofstream fin("a.txt");
if (!fin)
{
cout<<"File open error";
return;
}
char c[80] = "我是一个兵!";
fin.write(c,80);
fin.close();
}
●从文件中读取信息:
方式一:
#include <fstream.h>
void main()
{
fstream f("a.txt",ios::out);
f<<123<<3.14<<'A'<<"How are you";
f.close();
f.open("a.txt",ios::in);
int i;
double d;
char c;
char s[20];
f>>i>>d>>c;
f.getline(s,20);
cout<<i<<" "<<d<<" "<<c<<" "<<s<<endl;
f.close();
}
方式二:
#include <memory.h>
#include <fstream.h>
void main()
{
ifstream fin("a.txt",ios::nocreate);
if (!fin)
{
cout<<"File open error";
return;
}
char c[80];
memset(c,0,80);
while (!fin.eof())
{
fin.read(c,80);
cout<<c<<endl;
}
fin.close();
}
简单的复制文件:
#include <fstream.h>
void main()
{
ifstream fin("a.txt",ios::nocreate|ios::binary);
if (!fin)
{
cout<<"File open Error"<<endl;
return;
}
ofstream fout("b.txt",ios::binary);
char c[1024];
while (!fin.eof())
{
fin.read(c,1024);
fout.write(c,fin.gcount());
}
fin.close();
fout.close();
}