1 简介
1.1 继承关系
基类->继承类:
ios->ostream->ofstream
ios->istream->ifstream
iostream->fstream(还继承了两个缓冲区,一个用于输入,一个用于输出)(此类用于文件I/O的同步,即协调地移动输入缓冲区的输入指针和输出缓冲区的输出指针)(输入输出模式时使用fstream类)
1.2 流
C++程序将文件输入和输出看作字符流;对于输入来说,程序从输入流中抽取字符,对于输出来说,程序向输出流中插入字符。流是程序与流源或流目的之间的中介,这样C++就可以对来源不同的字符做相同处理。
1.3 缓冲区
缓冲区就是一块存储空间,它是为了匹配程序处理速度和外设处理速度;比如程序一次处理1byte,但是磁盘一次读取512bytes;又或者程序一次处理1byte,可以1byte地从磁盘读取,但是由于硬件读取一次数据复杂且操作慢,因此使用缓冲区可以加快程序处理速度。
flushing the buffer:刷新缓冲区就是清空缓冲区地内容以备下次使用。
文件输出输入使用缓冲区,在声明每个ofsream or ifsream对象时程序会为其自动分配该对象自己的缓冲区;使用缓冲区可以提高文件输出速度。
何时清空缓存:
1.缓存区满时
2.使用文件close()方法时,为了保证关闭文件时文件被更新。
2 输入输出流状态
流状态被定义为iostate,是由三个ios_base组成:eofbit, badbit, 和failbit,三者都为一位可以设置位1(设置)或0(清除)。当三者都为0时说明一切顺利。
成员 | 描述 |
---|---|
eofbit | 当读取文件到达文件尾时置为1 |
failbit | 当输入流中的数据类型和目的数据类型不一致时置为1;I/O错误(读取一个不允许访问的只读磁盘或打开一个不存在的文件)时置为1 |
badbit | 在一些无法诊断的失败破坏流时置为1 |
goodbit | 另一种说明0的方法 |
good() | 如果流可以使用,则返回true,反之返回false |
eof() | 如果eofbit被设置,则返回true,反之返回false |
bad() | 如果badbit被设置,则返回true,反之返回false |
fail() | 如果failbit或badbit被设置,返回true,反之返回false |
rdstate() | 返回流状态 |
exceptions() | 返回一个位掩码,指出哪些标记导致异常被引发 |
exceptions(iostate ex) | 设置哪些状态将导致clear()引发异常 |
clear(iostate s) | 将流状态设置为s,s的默认值为0;如果rdstate() & exceptions()) != 0,将抛出basic_ios::failure异常;将会设置s,但是其他的会被置0 |
setstate (iostate s) | 调用clear(rdstate()|s)。这将设置与s中设置的位对应的流的状态位,其他流状态保持不变。 |
2.1 设置状态
setstate()的主要目的是提供一种修改状态的途径。例如,如果num是一个int,则下面的调用将可能导致operator>>(int &)使用setstate()设置failbit或eofbit。
clear();//清除所有的位
clear(eofbit);//清除当前的位并设置为指定的位
setstate(eofbit);//设置指定的位
//等等
2.2 文件尾EOF
文件尾 EOF
如果输入来自于文件:使用文件尾(EOF)判断文件是否读完。
当检测到EOF之后:cin将eofbit和failbit都设置为1;同时,将设置cin对象中的一个指示EOF条件的标记,设置这个标记后,cin将不读取输入,直到cin.clear()。
EOF被定义为值为-1,因此不能将EOF赋给char类型,因为char类型没有符号,需要使用int类型接收EOF。
举例:Windows允许通过键盘模拟文件尾:Ctrl+Z
3 文件传输模式
ios_base定义了openmode类型表示模式,类似于fmtflags和iostate类型,是bitmask类型。
文件模式常量:
Constant | Meaning |
---|---|
ios_base::in | 读取文件 |
ios_base::out | 写入文件 |
ios_base::ate | 打开文件时文件指针指向文件尾 |
ios_base::app | 在文件尾添加内容 |
ios_base::trunc | 如果文件存在则截断它 |
ios_base::binary | 二进制文件 |
文件模式组合(|符号表示联合两个二进制为一个值,该值可以表达两个二进制模式)
C++ 模式 | C模式 | 含义 |
---|---|---|
ios_base::in | “r” | 读文件模式 |
ios_base::out | “w” | 与ios_base::out | ios_base::trunc一样 |
ios_base::out | ios_base::trunc | “w” | 写文件模式,并且在打开文件时截断文件(将文件置为空) |
ios_base::out | ios_base::app | “a” | 追加模式,将文件指针指向文件尾,向末尾添加内容;原始数据不可修改 |
ios_base::in | ios_base::out | “r+” | 打开以读写,在文件允许的位置写入 |
ios_base::in | ios_base::out | ios_base::trunc | “w+” | 打开以读写,如果文件已经存在,则首先截断文件 |
c++mode | ios_base::binary | “cmodeb” | 在C++模式和二进制模式打开 |
c++mode | ios_base::ate | “cmode” | 以指定的模式打开,并将文件指针移到文件尾。 |
模式的使用方法:
//第二个参数指定模式
//ifstream fin(filename, c++mode);
//fopen(filename, cmode);
ifstream fin("banjo", mode1); // constructor with mode argument
ofstream fout();
fout.open("harp", mode2); // open() with mode arguments
ifstream open()的默认模式为ios_base::in;
ofstream open()的默认模式为ios_base::out | ios_base::trunc;
fstream无默认模式,因此在创建fstream对象时要显示提高模式实参。
4 相关函数
4.1 ofstream对象 or ifstream对象.open(filename)
可以接受C-风格字符串作为参数,也可以接受存储在数组中的字符串
默认情况下,当filename所指文件不存在时,open()将在当前程序可执行目录创建名为filename的文件;
作用:当存在时,open()将首先截断该文件,即删除原有的文件内容,然后再将新内容输出到文件中
4.2 ofstream对象 or ifstream对象.close()
作用:无参数,原因是ofstream对象 or ifstream对象已经关联文件,不需要参数;在关闭文件时,不会释放ofstream对象 or ifstream对象的缓冲区,只是解除了ofstream对象 or ifstream对象与文件的关联关系;ofstream对象 or ifstream对象可以重新与其他文件绑定。
4.3 ofstream对象 or ifstream对象.isopen(filename)
检查文件filename是否被成功打开;如果成功打开,则返回true;反之(文件不存在等原因),返回false。
在流状态中的fin.fail()和fin.good()也能检查文件是否被正常打开,但是流状态相关函数不涉及文件传输模式;但是is_open()考虑了文件传输模式,因此is_open()更适用于检查文件是否正常打开。
4.4 ifstream对象.get(char ch)
作用:逐个字符获取文件中的内容,并将其赋值给ch;直到遇见文件尾。
4.5 ofstream对象.write( (char *) &pl, size);
第一个参数为要写入文件内容的地址(必须转换为char *类型),第二个参数为要写入内容的大小(单位为byte)。
作用:将pl指向的大小为size的内容复制到ofstream对象绑定的文件中。
注意事项:这个方法可以用于不含虚函数的类,原因是在这种情况下,只有数据成员被保存,而方法不会被保存;如果类有虚方法,则也将复制隐藏指针(该指针指向虚函数的指针表);由于下一次运行程序时,虚函数表可能在不同的位置,因此将文件中的旧指针信息复制到对象中,可能造成混乱。
4.6 ifstream对象.read((char *) &pl, size);
第一个参数为读入文件的存储地址(必须转换为char *类型),第二个参数为要读入内容的大小(单位为byte)。
作用:将ifstream对象绑定的文件中大小为size的内容pl指向的地址。
注意事项:这个方法可以用于不含虚函数的类,原因是在这种情况下,只有数据成员被保存,而方法不会被保存;如果类有虚方法,则也将复制隐藏指针(该指针指向虚函数的指针表);由于下一次运行程序时,虚函数表可能在不同的位置,因此将文件中的旧指针信息复制到对象中,可能造成混乱。
4.7 fstream对象 or istream对象.seekg()
将输入指针移动至给定文件位置(由于fstream对象使用缓冲区存取中间数据,因此指针指向的实际上是缓冲区的位置,而不是实际的文件)。
也可以将seekg()用于ifstream对象。
函数原型:
第一个原型定位到离第二个参数指定的文件位置的偏移量(单位为字节)的位置,第一个参数off_type为偏移量,第二个参数ios_base::seekdir可以为三个常量—ios_base::beg(相对于文件开始处的偏移)、ios_base::cur(相对于文件当前位置的偏移)、ios_base::end(相对于文件结尾处的偏移);
第二个原型定位到离文件开头特定距离(单位为字节)的位置,参数pos_type为偏移量。是一个绝对偏移量。
//模板原型
basic_istream<charT,traits>& seekg(off_type, ios_base::seekdir);
basic_istream<charT,traits>& seekg(pos_type);
//For the char specialization
istream & seekg(streamoff, ios_base::seekdir);
istream & seekg(streampos);//streampos包含一个接收streamoff参数的构造函数和一个接收整数参数的构造函数
//eg
fin.seekg(30, ios_base::beg); // 30 bytes beyond the beginning
fin.seekg(-1, ios_base::cur); // back up one byte
fin.seekg(0, ios_base::end); // go to the end of the file
注意:streampos和streampos是off_type和pos_type对于char类型的专门化;同样,针对wistream对象,wstreampos和streamoff类型是off_type和pos_type对于wistream类型的专门化。
4.8 fstream对象 or ostream对象.seekp()
将输出指针移动至给定文件位置(由于fstream对象使用缓冲区存取中间数据,因此指针指向的实际上是缓冲区的位置,而不是实际的文件)。
也可以将seekp()用于ofstream对象。
将输出指针移动至给定文件位置(由于fstream对象使用缓冲区存取中间数据,因此指针指向的实际上是缓冲区的位置,而不是实际的文件)。
也可以将seekp()用于ofstream对象。
函数原型:
第一个原型定位到离第二个参数指定的文件位置的偏移量(单位为字节)的位置,第一个参数off_type为偏移量,第二个参数ios_base::seekdir可以为三个常量—ios_base::beg(相对于文件开始处的偏移)、ios_base::cur(相对于文件当前位置的偏移)、ios_base::end(相对于文件结尾处的偏移);
第二个原型定位到离文件开头特定距离(单位为字节)的位置,参数pos_type为偏移量。是一个绝对偏移量。
//模板原型
basic_istream<charT,traits>& seekp(off_type, ios_base::seekdir);
basic_istream<charT,traits>& seekp(pos_type);
//For the char specialization
istream & seekp(streamoff, ios_base::seekdir);
istream & seekp(streampos);//streampos包含一个接收streamoff参数的构造函数和一个接收整数参数的构造函数
//eg
fin.seekp(30, ios_base::beg); // 30 bytes beyond the beginning
fin.seekp(-1, ios_base::cur); // back up one byte
fin.seekp(0, ios_base::end); // go to the end of the file
注意:streampos和streampos是off_type和pos_type对于char类型的专门化;同样,针对wistream对象,wstreampos和streamoff类型是off_type和pos_type对于wistream类型的专门化。
4.9 fstream对象 or istream对象.tellg()
返回值为streampos,表示输入指针的当前文件位置(单位为字节),相对于文件开始的偏移量。
注意:如果创建了fstream对象,由于输入指针和输出指针将同时移动,因此tellg()和tellp()返回值相同;然而,如果使用istream对象来管理输入流,而使用ostream对象管理输出流,则输入指针和输出指针将彼此独立移动,tellg()和tellp()返回值将不同。
4.10 fstream对象 or ostream对象.tellp()
返回值为streampos,表示输出指针的当前文件位置(单位为字节),相对于文件开始的偏移量。
注意:如果创建了fstream对象,由于输入指针和输出指针将同时移动,因此tellg()和tellp()返回值相同;然而,如果使用istream对象来管理输入流,而使用ostream对象管理输出流,则输入指针和输出指针将彼此独立移动,tellg()和tellp()返回值将不同。
4.11 fstream对象 or ostream对象 or istream对象.seekg(偏移量)
将文件指针指向距离文件开头 偏移量(单位为字节) 大小的位置。
可以使用它将文件指针指向文件开头。
5 简单文件输入输出
5.1 写入到文本文件中
步骤:
- 1 包含fstream头文件,fstream头文件中定义了ofstream类用于处理输出
- 2 包含std命名空间(ofstream在std命名空间中)
- 3 定义一个或多个ofstream对象,命名要求符合命名规范,每个ofstream对象都与一个输出流绑定在一起
- 4 将对象和文件关联起来,方法之一是open()方法,这种关联在对象释放时自动解除
- 5 文件操作完成时,应使用close()方法关闭文件
- 6 可以使用ofstream对象和<<操作符输出各种类型的数据,可以使用cout可使用的任何方法(cout使用方法见C++ cout的用法,看这一篇就够了)
5.2 读取文本文件
步骤:
- 1 包含fstream头文件,fstream头文件中定义了ifstream类用于处理输入,ifstream与一个输入流绑定在一起
- 2 包含std命名空间(ifstream在std命名空间中)
- 3 定义一个或多个ifstream对象,命名要求符合命名规范,每个ofstream对象都与一个输入流绑定在一起
- 4 将对象和文件关联起来,方法之一是open()方法
- 5 文件操作完成时,使用close()方法关闭文件
- 6 可以使用ifstream对象和>>操作符输出各种类型的数据,可以使用cin可使用的任何方法(cin使用方法见C++ cin的用法,看这一篇就够了)
- 7 ifstream本身作为测试条件时,如果最后一个读取操作成功,ifstream将被转换为true,否则转换为false
5.3 C++实例
5.3.1 cpp代码
/*
Project name : _26File
Last modified Date: 2022年4月29日22点20分
Last Version: V1.0
Descriptions: 简单文件输入输出
*/
#include <iostream>
#include <fstream> // for file I/O,这个头文件包含了iostream头文件,所以此处可以不显示包含iostream头文件
#include <cstdlib> // support for exit()
const int SIZE = 60;
int main()
{
using namespace std;
cout << "ofstream*********************************************************************" << endl;
char automobile[50];
int year;
double a_price;
double d_price;
string filename1;