全部博文(21)
分类: C/C++
2012-12-14 21:00:16
1.IO类型在三个独立的头文件中定义:iostream定义读写控制窗口的类型,fstream定义读写已命名文件的类型,而sstream定义的类型则用于读写存储在内存中的string对象.
2.IO对象不可复制或赋值,即表明
①无法将其存储在容器中
②形参或返回类型也不能为流类型,如果要传递或返回IO对象,则必须传递或返回指向该对象的指针或引用
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
流必须处于无错误状态,才能用于输入或输出。
badbit标志着系统级的故障,出现这类错误,则该流通常就不能再使用了,如果出现的是failbit可恢复的错误,通常是可以修正的
流的状态有bad,fail,eof和good操作揭示前三个和good相反;clear和setstate操作用于改变条件成员的状态
4.下面几种情况将导致缓冲区的内容被刷新,即写入到真实的输出设备或者文件:
①程序正常结束.作为main返回工作的一部分,将清空所有输出缓冲区.
②在一些不确定的时候,缓冲区可能已经满了,在这种情况下,缓冲区将会在写下一个值之前刷新
① 用操作符显式的舒心缓冲区,如endl(其实还有flush和ends)
② 在每次输出操作执行完后,用unitbuf操纵符设置流的内部状态从而清空缓冲区
③ 可将输出流与输入流关联起来.在这种情况下,在读输入流时将刷新缓冲区
警告:如果程序崩溃了,则不会刷新缓冲区
这一章在平时编程时一般是简单的使用,用于对文件的读写.
文件的读写是站在变量的角度讲的,读文件,就是从文件输出,写到变量,写文件,就是输入到文件,将变量写到文件
例子:
●创建并向文件写入信息:
点击(此处)折叠或打开
●从文件中读取信息:
方式一:
点击(此处)折叠或打开
点击(此处)折叠或打开
8.1 面向对象的标准库
先来看IO操作类图:
IO库大致可操作三类数据: 控制台流(stream) , 文件(file) , 字符串 (string)。
操作类型又可分三类:输入(in), 输出(out) ,输入与输出(in/out)。
ostream 是所有类型输出操作的基类
它扩展出两个子类: ofstream针对文件的输出操作类;ostringstream针对string的输出操作类
istream 是所有类型输入操作的基类
它扩展出两个子类: ifstream针对文件的输入操作类;istringstream针对string的输入操作类
ostream 和 istream共同扩展出类 iostream 它负责处理控制台stream的输入和输出
iostream 扩展出两个子类:stringstream专门处理string的输入输出; fstream专门处理文件的输入输出
所有类定义在不同头文件,正确使用类必须引入对应的头文件
iosteam头文件中定义了:
istream(从流中读取);
ostream(写到流中);
iostream(对流进行读写,从istream和osteam派生而来)
fsteam头文件中定义了:
ifstream(从文件中读取,由istream派生而来);
ofstream(写到文件中去,由ostream派生而来);
fstream(对文件进行读写,由iostream派生而来);
ssteam头文件中定义了:
istringstream(从string对象中读取,由istream派生而来);
ostringstream(写到string对象中去,由ostream派生而来);
stringstream(对string对象进行读写,由iostream派生而来);
要想正确使用IO类一定要理解他们的对应关系和每个类的职责。
c++的标准输入输出库iostream 是一个类库,以类的形式组织,使用该库中的类要先引用命名空间:using std;
最常使用的是cin和cout,这两个都是对象,cin是istream类的对象,cout是ostream类的对象,而输入的 cin>> 与输出时的 cout<< 中的左移 << 与右移 >> 分别是 istream 类与 ostream 类的操作符重载。
iostream库里面创建了3个标准流对象:
cin 表示标准输入的istream对象,cin可以使我们从设备读取数据。
cout 表示标准输出的ostream对象,cout可以使我们向设备写入数据。
cerr 表示标准错误的ostream对象,cerr是导出程序错误消息的地方,只能向屏幕设备写数据。
标准的流对象都有默认的设备:
cout << data ; cout默认的设备是显示器缓冲区。
cin >> data ; cin默认的设备是键盘缓冲区。
不管是输出到屏幕还是写入string或者保存到txt文本,字符都是不可获取的。通常我们不仅仅使用英文标准字符,我们还可能输入输出中文字符或其他非英文字符。这时候需要国际字符支持。
例如我们要保存一个字符 'a' 可以定义 char, 但是我们要保存字符 '家' 就无法按使用char 而要使用 wchar_t 了。IO类也有这样的区分,例如我们要在控制台输出中文字符就只能用 wcout << "你好" << endl想要将中文保存到文本就要用wofstream 或 wfstream 。要正确读取包含中文字符文件要使用 wifstream 类。
IO对象无法复制或者赋值,所以io对象作为函数形参或返回值时只能使用指针或引用。
iostream &Getio(iostream &io, fstream *fs){ ...} // 正确,参数和返回以引用或指针形式传递
iostream Getio(iostream io){ ...} // 错误,参数和返回以拷贝方式传递会发生复制和赋值操作
8.2 条件状态
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
strm是一种具体的流。
这么多操作我们该如何理解呢。
上面说过,任何一个IO对象在任意时刻都有一种状态。iostate 就是代表状态的枚举。badbit,failbit,eofbit,goodbit是iostate的一个具体值,看下面代码
点击(此处)折叠或打开
8.3 输出缓冲区的管理
关于缓冲区内容
这里介绍tie()函数用法,函数可将输出流与输入流关联起来,在这种情况下在读取输入流时将刷新关联的输出流,下面代码解释了含义:
点击(此处)折叠或打开
tie()关联之后第一次执行到 cin 语句系统会立刻刷新关联的输出流,所以内容会立刻写入文件不必等到main执行完毕。
8.4 文件流对象的使用
C++ 通过以下几个类支持文件的输入输出:
ofstream: 写操作(输出)的文件类 (由ostream引申而来)
ifstream: 读操作(输入)的文件类(由istream引申而来)
fstream: 可同时读写操作的文件类 (由iostream引申而来)
打开文件(Open a file)
对这些类的一个对象所做的第一个操作通常就是将它和一个真正的文件联系起来,也就是说打开一个文件。被打开的文件在程序中由一个流对象(stream
object)来表示 (这些类的一个实例) ,而对这个流对象所做的任何输入输出操作实际就是对该文件所做的操作。
要通过一个流对象打开一个文件,我们使用它的成员函数open() :
void open (const char *filename, openmode mode) ;这里filename 是一个字符串,代表要打开的文件名,mode 是以下标志符的一个组合:
ios::in | 为输入(读)而打开文件 |
ios::out | 为输出(写)而打开文件 |
ios::ate | 初始位置:文件尾 |
ios::app | 所有输出附加在文件末尾 |
ios::trunc | 如果文件已存在则先删除该文件 |
ios::binary | 二进制方式 |
这些标识符可以被组合使用,中间以”或”操作符(|)间隔。例如,如果我们想要以二进制方式打开文件"example.bin" 来写入一些数据,我们可以通过以下方式调用成员函数open() 来实现:
ofstream file ;
file.open ("example.bin", ios::out | ios::app | ios::binary) ;
ofstream, ifstream 和 fstream所有这些类的成员函数open 都包含了一个默认打开文件的方式xxstream.open("filepath") ,这三个类的默认方式各不相同:
类 | 参数的默认方式 |
---|---|
ofstream | ios::out | ios::trunc |
ifstream | ios::in |
fstream | ios::in | ios::out |
只有当函数被调用时没有声明方式参数的情况下,默认值才会被采用。如果函数被调用时声明了任何参数,默认值将被完全改写,而不会与调用参数组合。
由于对类ofstream, ifstream 和 fstream 的对象所进行的第一个操作通常都是打开文件,这些类都有一个构造函数可以直接调用open 函数,并拥有同样的参数。这样,我们就可以通过以下方式进行与上面同样的定义对象和打开文件的操作:
ofstream file("example.bin", ios::out | ios::app | ios::binary);
// 等价于
ofstream file ;
file.open("example.bin",ios::out | ios::app | ios::binary) ;
两种打开文件的方式都是正确的。你可以通过调用成员函数is_open()来检查一个文件是否已经被顺利的打开了:
检测文件是否打开:bool is_open() ;它返回一个布尔(bool)值,为真(true)代表文件已经被顺利打开,假( false )则相反。打开文件后判断是好的习惯。
关闭文件(Closing a file)当文件读写操作完成之后,我们必须将文件关闭以使文件重新变为可访问的。关闭文件需要调用成员函数close(),它负责将缓存中的数据排放出来并关闭文件。它的格式很简单:void close();
这个函数一旦被调用,原先的流对象(stream object)就可以被用来打开其它的文件了,这个文件也就可以重新被其它的进程(process)所有访问了。
为防止流对象被销毁时还联系着打开的文件,析构函数(destructor)将会自动调用关闭函数close。
文本文件(Text mode files)类ofstream, ifstream 和fstream 是分别从ostream, istream 和iostream 中引申而来的。这就是为什么 fstream 的对象可以使用其父类的成员来访问数据。
一般来说,我们将使用这些类与同控制台(console)交互同样的成员函数(cin 和 cout)来进行输入输出。如下面的例题所示,我们使用重载的插入操作符<<
点击(此处)折叠或打开
This is a line.
This is another line.
从文件中读入数据也可以用与 cin的使用同样的方法:
点击(此处)折叠或打开
除了eof()以外,还有一些验证流的状态的成员函数(所有都返回bool型返回值):
如果在读写过程中出错,返回 true 。例如:当我们要对一个不是打开为写状态的文件进行写入时,或者我们要写入的设备没有剩余空间的时候。系统错误,无法修复的。
除了与bad() 同样的情况下会返回 true 以外,加上格式错误时也返回true ,例如当想要读入一个整数,而获得了一个字母的时候。
如果读文件到达文件末尾,返回true。
这是最通用的:如果调用以上任何一个函数返回true 的话,此函数返回 false 。
要想重置以上成员函数所检查的状态标志,你可以使用成员函数clear(),没有参数。
所有输入/输出流对象(i/o streams objects)都有至少一个流指针:
我们可以通过使用以下成员函数来读出或配置这些指向流中读写位置的流指针:
这两个成员函数不用传入参数,返回pos_type 类型的值(根据ANSI-C++ 标准) ,就是一个整数,代表当前get 流指针的位置 (用tellg) 或 put 流指针的位置(用tellp).
这对函数分别用来改变流指针get 和put的位置。两个函数都被重载为两种不同的原型:
使用这个原型,流指针被改变为指向从文件开始计算的一个绝对位置。要求传入的参数类型与函数 tellg 和tellp 的返回值类型相同。
seekg ( off_type offset, seekdir direction ) ;
seekp ( off_type offset, seekdir direction ) ;
使用这个原型可以指定由参数direction决定的一个具体的指针开始计算的一个位移(offset)。它可以是:
ios::beg | 从流开始位置计算的位移 |
ios::cur | 从流指针当前位置开始计算的位移 |
ios::end | 从流末尾处开始计算的位移 |
流指针 get 和 put 的值对文本文件(text file)和二进制文件(binary file)的计算方法都是不同的,因为文本模式的文件中某些特殊字符可能被修改。由于这个原因,建议对以文本文件模式打开的文件总是使用seekg 和 seekp的第一种原型,而且不要对tellg 或 tellp 的返回值进行修改。对二进制文件,你可以任意使用这些函数,应该不会有任何意外的行为产生。
以下例子使用这些函数来获得一个二进制文件的大小:
点击(此处)折叠或打开
在二进制文件中,使用<< 和 >>,以及函数(如getline)来操作符输入和输出数据,没有什么实际意义,虽然它们是符合语法的。
文件流包括两个为顺序读写数据特殊设计的成员函数:write 和 read。第一个函数 (write) 是ostream 的一个成员函数,都是被ofstream所继承。而read 是istream 的一个成员函数,被ifstream 所继承。类 fstream 的对象同时拥有这两个函数。它们的原型是:
这里 buffer 是一块内存的地址,用来存储或读出数据。参数size 是一个整数值,表示要从缓存(buffer)中读出或写入的字符数。
点击(此处)折叠或打开
当我们对文件流进行操作的时候,它们与一个streambuf 类型的缓存(buffer)联系在一起。这个缓存(buffer)实际是一块内存空间,作为流(stream)和物理文件的媒介。例如,对于一个输出流, 每次成员函数put (写一个单个字符)被调用,这个字符不是直接被写入该输出流所对应的物理文件中的,而是首先被插入到该流的缓存(buffer)中。
当缓存被排放出来(flush)时,它里面的所有数据或者被写入物理媒质中(如果是一个输出流的话),或者简单的被抹掉(如果是一个输入流的话)。这个过程称为同步(synchronization),它会在以下任一情况下发生:
在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:
1、插入器 (<<)
向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'n';就表示把字符串"Write Stdout"和换行字符('n')输出到标准输出流。
2、析取器 (>>)
从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。
在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。
一、打开文件
在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:
void open(const char* filename, int mode, int access) ;
参数:
filename: 要打开的文件名
mode: 要打开文件的方式
access: 打开文件的属性
打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:
ios::app: 以追加的方式打开文件
ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性
ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文
ios::in: 文件以输入方式打开
ios::out: 文件以输出方式打开
ios::nocreate: 不建立文件,所以文件不存在时打开失败
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
ios::trunc: 如果文件存在,把文件长度设为0
可以用“或”把以上属性连接起来,如 ios::out| ios::binary
打开文件的属性取值是:
0:普通文件,打开访问
1:只读文件
2:隐含文件
4:系统文件
可以用“或”或者“+”把以上属性连接起来 ,如3或 1|2 就是以只读和隐含属性打开文件。
例如:以二进制输入方式打开文件c:config.sys
fstream file1 ;
file1.open("config.sys", ios::binary | ios::in,0) ;
如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
file1.open("config.sys") ; 等价于 file1.open("config.sys",ios::in|ios::out,0) ;
另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:
fstream file1("config.sys") ;
特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file
stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。
ifstream file2("dos.def") ; //以输入方式打开文件
ofstream file3("x.123") ; //以输出方式打开文件
所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。
二、关闭文件
打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。
三、读写文件
读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式
1、文本文件的读写
文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:
file2<<"I Love You" ; // 向文件写入字符串"I Love You"
int i ;
file1 >> i ; // 从文件输入一个整数值。
这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
操纵符 功能 输入/输出
dec 格式化为十进制数值数据 输入和输出
endl 输出一个换行符并刷新此流 输出
ends 输出一个空字符 输出
hex 格式化为十六进制数值数据 输入和输出
oct 格式化为八进制数值数据 输入和输出
setpxecision(int p) 设置浮点数的精度位数 输出
比如要把123当作十六进制输出:file1<
①put()
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
②get()
get()函数比较灵活,有3种常用的重载形式:
一种就是和put()对应的形式:ifstream &get(char &ch) ;功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。
另一种重载形式的原型是: int get() ;这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。
还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='n') ;这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'n'。例如:
file2.get(str1,127,'A') ; // 从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。
③读写数据块
要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:
read(unsigned char *buf,int num) ;
write(const unsigned char *buf,int num) ;
read()
从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int
gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是
unsigned char *,有时可能需要类型转换。
例:
unsigned char str1[]="I Love You";
int n[5];
ifstream in("xxx.xxx");
ofstream out("yyy.yyy");
out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中
in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换
in.close(); out.close();
四、检测EOF
成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();
例: if(in.eof()) ShowMessage("已经到达文件尾!") ;
五、文件定位
和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时相应的指针自动变化。
所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是 seekg()和 seekp(),seekg()是设置读位置,seekp是设置写位置。它们最通用的形式如下:
istream &seekg(streamoff offset,seek_dir origin);
ostream &seekp(streamoff offset,seek_dir origin);
streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
ios::beg: 文件开头
ios::cur: 文件当前位置
ios::end: 文件结尾
这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。
例:
file1.seekg(1234,ios::cur) ; //把文件的读指针从当前位置向后移1234个字节
file2.seekp(1234,ios::beg) ; //把文件的写指针从文件开头向后移1234个字节
最大行业软件2012-12-30 11:10:03
ANSA.v14.0.Pre.16.11.2012.Win32_64 1CD
Beta-CAE MetaPost 6.8.2 Win32_64 1CD
CMG Suite v2012.0 Win32-ISO 1DVD
CMG Suite v2012.0 Win64-ISO 1DVD
Delcam.PowerShape.2013.SP6.Update.Only.Win32_64 2CD
ESI PAM-Stamp 2G 2012.0 Linux32_64 1DVD
Surpac v6.3.2 Win32 1CD
Topcon.Tools.v8.2 1CD
Embird Plus v8.0 1CD
Keil RealView Microcontroller Development Kit 4.60 1CD