一、I/O流
C++把对文件的读写操作都封装在了以下类中:
ofstream 对文件的写操作,继承了ostream类的功能
ifstream 对文件的读操作,继承了istream类的功能
fstream 对文件的读写操作,继承了ofstream、ifstream类的功能
二、C++对文件进行读写的步骤:
1、创建流对象,打开文件
#include <fstream>
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 类的默认mode
只读打开文件,文件不存在则打开失败 r
ofstream 类的默认mode
只写打开文件,文件不存在则创建,文件存在则清空。 w
fstream 类的默认mode r+
以读写打开文件,文件不存在则打开失败
注意:这些打开模式单独使用和混合使用的功能有相就的删减,不是简单的功能相加,具体功能可使用 strace 追踪它们底层调用open函数对应
2、判断文件是否打开成功
bool good();
功能:判断上一次操作是否成功,可用于判断文件是否打开。
返回值:
true:打开成功
false:打开失败
3、流对象<< 写操作、流对象>> 读操作
ofs << str << endl;
ifs >> str;
4、关闭文件
void close();
练习1:设计一个学生类并创建对象,然后把对象以文本格式写入stu.txt文件中。
练习2:从stu.txt文件中读写学生类并显示。
注意:在读写类对象时,由于绝大多数成员都是private属性,因此不能在类外进行读写,且由于ostream/istream是ifstream/ofstream/fstream的父类,因此实现<</>>运算符函数既可以用于输入输出对象,也可以用于文本格式的读写。
三、随机读写
C++为流提供了两套设置位置指针的成员函数,为了兼容有两个位置指针系统,但由于Linux和windows系统底层只有一个位置指针,所以使用其中套即可。
istream &seekg( off_type offset, ios::seekdir origin );
功能:偏移值+基础位置设置输入流的位置指针
origin:
ios::beg 文件开头
ios::end 文件末尾
ios::cur 当前位置
istream &seekg( pos_type position);
功能:按绝对位置设置输入流的位置指针
ostream &seekp( off_type offset, ios::seekdir origin );
功能:偏移值+基础位置设置输出流的位置指针
ostream &seekp( pos_type position );
功能:按绝对位置设置输出流的位置指针
pos_type tellg();
功能:获取输入流的位置指针
pos_type tellp();
功能:获取输出流的位置指针
#include <iostream>
#include <fstream>
#include <string.h>
using namespace std;
class Student
{
char name[20];
char sex;
short age;
public:
Student(const char* name,char sex,short age):sex(sex),age(age)
{
strcpy(this->name,name);
}
friend ostream& operator<<(ostream& os,const Student& stu)
{
return os << stu.name << " " << stu.sex << " " << stu.age;
}
friend istream& operator>>(istream& is,Student& stu)
{
return is >> stu.name >> stu.sex >> stu.age;
}
};
int main(int argc,const char* argv[])
{
Student stu("hehe",'m',28);
fstream fs("text.txt");
if(!fs.good())
return -1;
fs << stu << endl;
Student stu1("",'w',0);
fs.seekg(0,ios::beg);
fs >> stu1;
cout << stu1 << endl;
fs.close();
}
四、C++对二进制文件进行读写
1、打开文件
使用构造函数,open函数打开文件,mode参数增加ios::binary。
2、读写
istream &read( char *buffer, streamsize num );
buffer:存储数据的缓冲区首地址
num:缓冲区的大小
streamsize gcount();
功能:获取最后一次读到的字节数
ostream &write( const char *buffer, streamsize num );
buffer:待写入数据的内存首地址
num:数据的字节数
使用good函数判断是否写入成功。
3、关闭文件
void close();
注意:在写入对象时,对象的成员中不应该有指针(string)类型的成员。
bool eof();
功能:判断文件是否到达末尾
while(true)
{
// 读操作 fs>>obj fs.read
if(fs.eof())break;
// 其它操作
}
int main(int argc,const char* argv[])
{
fstream fs("stu.dat",ios::binary|ios::out|ios::in);
if(!fs.good())
cout << "打开失败!" << endl;
fs.seekg(0,ios::end);
Student* stu = new Student("hehe",'m',18);
Student* stu1 = new Student("",'w',0);
fs.write((char*)stu,sizeof(Student));
fs.seekg(0,ios::beg);
fs.read((char*)stu1,sizeof(Student));
cout << *stu1 << endl;
cout << fs.gcount() << endl;
char buf[4096] = {};
fs.seekg(0,ios::beg);
while(true)
{
fs.read((char*)stu1,sizeof(Student));
cout << *stu1 << endl;
if(fs.eof()) break;
}
fs.close();
}
五、类型信息
C++中的typeid可以获取数据的类型,使用时需要加头文件typeinfo。
1、返回值是type_info类型对象
2、type_info的name成员函数可以获取类型名
3、它还实现了==运算符,可以判断两个数据是否是同一种类型。
4、它可以区别父类指针或引用指向的是哪个子类,但前提是父子类之间构造了多态。
作业:实现一个C++版mv命令。
stat
移动文件
源文件是普通文件
重命名 目标不能被打开
不重命名 目标能打开
目标是目录
目标是文件,是否覆盖
重命名
源文件和目标文件在同目录下
目录移动
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc,const char* argv[])
{
if(3 != argc)
{
cout << "Use:mv <src> <dest>" << endl;
return -1;
}
ifstream ifs(argv[1]);
if(!ifs.good())
{
cout << "源文件不存在,请检查" << endl;
return -1;
}
if(0==access(argv[2],F_OK))
{
cout << "源文件已存在,是否覆盖(y/n)?";
char cmd;
cin >> cmd;
if(cmd != 'y')
{
cout << "停止移动!" << endl;
ifs.close();
return 0;
}
}
ofstream ofs(argv[2]);
if(!ofs.good())
{
cout << "目标位置无权限,请检查!" << endl;
return -1;
}
char buf[4096];
do{
ifs.read(buf,sizeof(buf));
ofs.write(buf,ifs.gcount());
}while(!ifs.eof());
ifs.close();
ofs.close();
remove(argv[1]);
}
可以写在简历中的小工具
mv命令
ping命令
rm -rf命令
ls -la命令
cp多线程