一、I/O流
头文件 <fstream>
C++中把对文件的读写操作都封装在以下类中:
ofstream 对文件的写操作,继承了 ostream类的功能
ifstream 对文件的读操作,继承了 istream类的功能
fstream 对文件的读写操作,继承了ofstream/ifstream
二、C++对文本文件的读写操作
1、创建流对象,通过流对象打开文件
a、创建流对象并用有参构造打开文件
ofstream fout(const char *filename,<openmode mode>);
b、无参构造创建流对象,再通过成员函数打开文件
void open( const char *filename);
void open( const char *filename,openmode mode);
mode:文件的打开方式
ios::app 添加输出
ios::ate 当已打开时寻找到EOF
ios::binary 以二进制模式打开文件
ios::in 为读取打开文件
ios::out 为写入打开文件
ios::trunc 覆盖存在的文件
ifstream类 默认只读方式打开文件,文件不存在则失败 r
ofstream类 默认只写方式打开文件,文件不存在则创建,存在则清空 w
fstream类 默认读写方式打开文件,文件不存在则失败 r+
2、判断文件是否打开成功
a、使用类对象名的方式进行判断
if(!fin) //失败
else //成功
b、使用good/fail 成员函数进行判断上一次文件操作是否成功/失败 需要注意返回值
3、读写文件
流对象 << 文本数据 写操作
流对象 >> 变量 读操作
4、关闭文件
close();
注意:只是关闭流对象的当前打开文件,但是流对象依然可以继续打开新文件
练习1:
设计一个学生类并创建学生对象,然后把对象的内容以文本形式写入stu.txt中
联系2:
从stu.txt中读取出来,并用该内容实例化一个新的学生对象并显示
注意:在读写内建类型数据时,原有的 << >> 运算符就可以直接进行文本读写,但是在对类对象进行读写操作时,绝大多数的类成员变量
是private,因此无法直接在类外进行读写
由于ostream/istream是ofstream/ifstream的父类,因此如果在它们里面重载了 << >> 运算符,那么除了可以直接通过cout/cin
输入输出类对象外,还可以用于直接文本读写类对象,一举两得
三、C++的随机读写
C++为文件IO流提供了两套设置文件位置指针的成员函数,目的为了兼容有两个位置指针的操作系统,但是UNIX/Linux和Windows系统
底层只有一个位置指针,所以使用哪套都可以
istream &seekg(off_type offset,ios::seekdir origin);
功能:通过偏移值+基础位置 设置 输入流位置指针的位置
offset:偏移量
origin:基础位置
ios::beg 文件开头
ios::cur 文件位置
ios::end 文件末尾
istream &seekg(pos_type position);
功能:通过 绝对位置 设置输入流位置指针的位置
ostream &seekp( off_type offset, ios::seekdir origin );
ostream &seekp( pos_type position );
功能与seekg类似,用哪个都可以
pos_type tellg();
功能:获取输入流的位置指针的位置
pos_type tellp();
功能:获取输出流的位置指针的位置
bool eof();
功能: 判断文件的上一次读操作是否从文件末尾开始读,是返回真
四、C++对二进制文件的读写操作
1、创建流对象,打开文件
a、使用有参构造创建并打开、
b、使用无参构造创建对象,通过open成员函数打开文件
mode参数增加 ios::binary (Windows下一定要加)
2、二进制读写操作
ostream &write(const char *buffer,streamsize num);
功能: 以二进制方式写入文件
buffer: 待写入数据的内存首地址
num:要写入的字节
注意:C++中文件I/O流的write只有两种结果,要么num个字节全部写入成功,要么一个都没有写入,只需要使用
good/fail 判断是否写入成功
istream &read(char *buffer, streamsize num);
功能:以二进制方式读文件
buffer:存储数据的内存首地址
num:要读取的字节数
streamsize gcount();
功能:获取上一次读文件操作时读到的字节数
注意:在以二进制方式读写对象时,对象的成员不应该有指针(以及string)类型,因为在写入时只会写入指针成员变量(地址编号),而
下一次读取该指针变量时,该指针所指向的内存极大可能不是指向上次写入时的内存了,因此读到的该编号没意义了
一直读二进制文件到末尾
while(true)
{
//读操作 read fin >> obj
if(fs.eof()) break;
//其他操作
}
练习3: 使用C++实现mv命令(实现带覆盖提示即可)
mv dest src
移动文件
源文件是普通文件
目标不是当前路径 创建打开目标文件
目标只是个路径 新建同名文件,移动删除
目标是路径+文件名 存在则判断是否覆盖
不存在则新建并移动
目标是当前路径 重命名 rename
移动目录
源文件是目录文件 通过LinuxC 打开目录流
可以写在简历、自我介绍上自己实现的小工具:
1、ls -al
2、cp 多线程
3、mv 命令
4、ping 命令
5、rm -rf
五、类型信息识别
C++中使用typeid运算符可以获取数据的类型
必须加头文件 #include <typeinfo>
cout << typeid(数据)
1、返回值是一个类类型对象
2、该类类型中有一个name成员函数,可以获取数据的类型并转换为字符串
3、该类重载了 == 运算符 可以判断两个数据是否是同一个类型
4、它可以区别父类指针或引用指向的是哪个子类,但是前提是父子类之间构成多态