一、C++ I/O流
头文件:fstream
C++把对文件的读写操作都封装在以下的类中:
ofstream类对文件的写操作,继承了ostream类的功能
ifstream类对文件的读操作,继承了istream类的功能
fstream类对文件读写操作,继承了ofstream、ifstream类的功能
二、C++对文本文件的读写
1、创建流对象,通过流对象打开文件
①ofstream ofs(const char *filename, openmode mode );
②通过成员函数方式,打开文件
void open( const char *filename );
void open( const char *filename, openmode mode );
filename:文件的路径
mode: 打开方式
参数 | 操作 |
---|---|
ios::app | 添加输出 |
ios::ate | 当已打开时寻找到EOF |
ios::binary | 以二进制模式打开文件 |
ios::in | 为读取打开文件 |
ios::out | 为写入打开文件 |
ios::trunc | 覆盖存在的文件 |
ifstream类,默认以只读方式O_RDONLY打开文件,文件不存在则失败 “r”
ofstream类,默认以只写方式O_WRONLY|O_CREAT|O_TRUNC打开文件,文件不存在则创建、存在则清空 “w”
fstream类 默认以读写方式O_RDWR打开文件,文件不存在则失败,文件存在不清空 “r+”
注意:ios::里面打开模式单独使用和混合使用时候有些功能会有所删减变化,不是简单的功能相加,具体底层调用哪个打开模式可以通过 strace ./a.out 来追踪底层对系统函数的调用
2、如何判断文件是否打开成功
①通过 !流对象名 执行了该类的!运算符重载版本
if(!ifs) // 为真 失败
②通过good\fail成员函数判断是否成功
bool good();
功能:判断上一次流操作是否成功,成功返回真,一般用于判断文件是否打开成功
3、读写文件
流对象 << 写操作
流对象 >> 读操作
4、关闭文件
成员函数:
void close(void)
注意:只是关闭流对象当前的文件,但是流对象没有销毁,还可以继续通过open成员函数重新打开别的文件
5、如何以文本方式读写类对象
读写类对象时绝大部分成员变量都是私有的,因此无法直接在类外进行读写
由于ostream/istream分别是ofstream/ifstream的父类,因此如果重载了>> <<运算符,既可以用于平时输出、输入类对象,并且还可以直接用于类对象的文本方式流操作读写
重载前 | 重载后 |
---|---|
cout << 类对象 | ofs << 类对象 |
cin >> 类对象 | ifs >> 类对象 |
三、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 );
功能:通过绝对值的方式设置位置指针的位置
seekp 功能类似
pos_type tellp();
功能:获取位置指针所在文件的绝对位置
tellg功能类似
四、C++对二进制文件的读写操作
1、创建流对象、打开文件
ios::binary 以二进制模式打开文件
2、读写操作
ostream &write( const char *buffer, streamsize num );
功能:以二进制方式写文件
buffer:待写入数据的内存首地址
num:待写入的字节数
注意:C++的write只会有两种结果,要么num个字节全部写入,要么一个都没写入,可以通过good、fail判断上一次的写操作是否成功
istream &read( char *buffer, streamsize num );
功能:以二进制方式读文件
buffer:存储读取到的数据的内存首地址
num:要读取的字节数
streamsize gcount();
功能:获取上一次读操作中成功读取到的字节数
bool eof();
功能:判断读操作是否读到了文件末尾,如果是返回真
3、二进制读写需要注意的问题:
①对象的成员变量中不应该有指针类型(或string类型),因为此时写入时只会把指针变量存储的地址写入,而下次读取到该指针变量时,该指针地址已经没有意义了
②一直读取二进制文件
while(true)
{
// 读操作
if(fs.eof()) break;
// 读成功,执行相应操作
}
使用C++实现一个简易mv带覆盖检查的命令
#include <iostream>
#include <unistd.h>
#include <fstream>
using namespace std;
int main(int argc,const char* argv[])
{
if(3 != argc)
{
cout << "User: ./MV <src> <dest>" << endl;
return -1;
}
ifstream ifs(argv[1]);
if(!ifs)
{
cout << "原文件不存在,请检查!" << endl;
return -1;
}
if(0 == access(argv[2],F_OK))
{
cout << "目标文件已存在,是否覆盖(y/n)?" << endl;
char cmd;
cin >> cmd;
if('y' != cmd)
{
cout << "停止移动!" << endl;
ifs.close();
return 0;
}
}
ofstream ofs(argv[2]);
if(!ofs)
{
cout << "目标位置无权限,请检查!" << endl;
ifs.close();
return -1;
}
char buf[4096] = {};
while(true)
{
ifs.read(buf,sizeof(buf));
if(ifs.eof()) break;
ofs.write(buf,ifs.gcount());
}
ifs.close();
ofs.close();
unlink(argv[1]);
}