黑马程序员课程学习笔记
文件操作
程序运行的数据都是临时的,运行结束后会被释放。要想永久存储数据,需要用到文件。c++中对文件操作需包含头文件 < fstream >
。文件类型有两种:文本文件和二进制文件。
操作文件的三大类:
- ofstream:写操作
- ifstream:读操作
- fstream:读写操作
文本文件
写文件
除了可以保存成txt,也可以保存成csv,信息之间用逗号分隔,csv文件既可以用记事本打开,也可以用Excel打开
- 包含头文件 fstream
- 创建流对象 ofstream ofs;
- 打开文件 ofs.open(“文件路径\\文件名”,打开方式),因为一个反斜杠是转义字符
- 写数据 ofs<<"写入的数据”<<endl;
- 关闭文件 ofs.close()
文件打开方式
打开方式 | 解释 |
---|---|
ios::in | 为读文件而打开文件 |
ios::out | 为写文件而打开文件 |
ios::ate | 打开后就跳到文件尾 |
ios::app | 追加方式写文件 |
ios::trunc | 文件存在,则删除后建立空白文件;文件不存在,直接建立空白文件,不需要另外判断 |
ios::binary | 二进制方式 |
如果要用到多个打开方式,利用 |
eg:二进制方式写文件 ios::binary | ios::out
注意:
- 文件路径,要用\\隔开,因为单反斜杠是转义字符,再加一个反斜杠才能表示\
- 也可以不写文件路径,直接写文件名,将被保存在该cpp所在文件夹
#include <iostream>
#include <fstream>
using namespace std;
int main() {
//1.包含头文件 fstream
//2.创建流对象
ofstream ofs;//out file stream
//3.打开文件
//可以直接写文件名,会默认保存在该cpp所在文件夹啊
//特别注意:反斜杠是转义字符,只有双反斜杠才是一个反斜杠,代表路径
ofs.open("E:\\杂七杂八\\新建文件夹 (3)\\c++知识回顾\\09 文件操作\\myFile\\test.txt", ios::out);
//4.写数据
ofs << "姓名:张三" << endl;
ofs << "性别:男" << endl;
ofs << "年龄:23" << endl;
//5.关闭文件
ofs.close();
system("pause");
return 0;
}
读文件 中文字符串乱码
特别注意:如果读取txt中的中文字符串乱码,有可能是编码格式造成的,
解决方法:`打开txt文件>另存为>底下编码格式选择ANSI>替换源文件==
- 包含头文件 fstream
- 创建流对象 ifstream ifs;
- 打开文件,并判断是否打开成功 ifs.open("文件路径”,打开方式);
- 读数据 有4种方式
- 关闭文件 ifs.close()
注意包含头文件fstream和string,推荐方式3
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//读文件
//对读到的文件进行输出操作,共有4中方式,方式3更易理解和操作
//方式4是逐个读字符,效率低,且注意括号位置
void test01() {
//1.包含头文件 fstream
//2.创建流对象
ifstream ifs;//in file stream
//3.打开文件,并判断是否打开成功
string filePath = "E:\\杂七杂八\\新建文件夹 (3)\\c++知识回顾\\09 文件操作\\myFile\\test.txt";
ifs.open(filePath, ios::in);
if (!ifs.is_open()){//如果ifs没有打开文件
cout << filePath << "\t打开失败" << endl;
return;//不能在main函数中return 因为main的返回值类型是int
}
//4.读数据
//4.1 方式1
//char buf[1024] = { 0 };//创建一个字符数字,全为0(打印并不会输出0)
//while (ifs >> buf)
//{
// cout << buf << endl;
//}
//4.2 方式2
//char buf[1024] = { 0 }; //初始化
//while (ifs.getline(buf,sizeof(buf)))
//{
// //getline是ifs自带的函数成员函数,获取一行,有两个参数
// //第一个传入数组名,第二个是数组长度
// cout << buf << endl;
//}
//4.3 方式3
string buf;
//通过全局函数getline,把文件输出流ifs,读取到字符串buf
//也不一定是getline 直接ifs>>buf 也可以读到,比较灵活
while (getline(ifs,buf))
{
cout << buf << endl;
}
4.4 方式4
//char c;
c = ifs.get();每次读一个字符,存到c,如果没有读到文件尾,就一直循环
//while ((c=ifs.get())!=EOF)//eof end of file
//{
// cout << c;
//}
//5.关闭文件
ifs.close();
}
int main() {
test01();
system("pause");
return 0;
}
二进制文件
二进制文件的优势在于,文件打开时乱码的,有种加密的效果。此外,二进制文件除了可以对内置数据类型进行操作之外,还可以操作自定义的数据类型,如类。
二进制写文件
这里定义了一个Person类,存在文件中。
注意:
- 步骤基本相同,写数据用的write函数
- 字符串类型不能用string,会乱码。得用char数组。
- 因为char数组的特殊性,不能用实例化对象再赋值的方式,得用结构体类似的大括号,且顺序与成员变量定义顺序一致。详见结构体
- 有参构造也不行
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
//二进制写文件,不仅可处理内置数据类型,还可处理自定义数据类型
class Person{
public:
char m_Name[64];
int m_Age;
};
void test01() {
//1.包含头文件
//2.创建流对象,其实2和3可以并作一步
//因为ofstream构造函数可以赋初值
//ofstream ofs("Person.txt", ios::out | ios::binary);
ofstream ofs;
//3.打开文件
ofs.open("E:\\杂七杂八\\新建文件夹 (3)\\c++知识回顾\\09 文件操作\\myFile\\binary.txt", ios::out | ios::binary);
//4.写数据
Person p = { "张三",22 };//类与结构体类似,结构体有两种赋值方式,一种是先实例化再. 另一种就是这种大括号
//Person p;
//p.m_Name = "李四";//不能这么写,字符串数组不能这么设置
//p.m_Age = 22;
//也不可以用构造函数
//因为wirte要求的参数类型是const char*,所以强转换
ofs.write((const char*)&p, sizeof(Person));//Person也可以换成对象p
//5.关闭文件
ofs.close();
}
int main() {
test01();
system("pause");
return 0;
}
二进制读文件
二进制读文件,得和写数据意义,定义一个相同的类去接收。用到了read函数。
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
//二进制读文件
class Person {
public:
char m_Name[64];
int m_Age;
};
void test01() {
//1.包含头文件
//2.创建流对象
ifstream ifs;
//3.打开文件
ifs.open("E:\\杂七杂八\\新建文件夹 (3)\\c++知识回顾\\09 文件操作\\myFile\\binary.txt", ios::in | ios::binary);
if (!ifs.is_open())
{
cout << "文件打开失败" << endl;
return;
}
//4.读文件
Person p;
//因为wirte要求的参数类型是const char*,所以强转换
ifs.read((char*)&p, sizeof(p));
cout << "姓名:" << p.m_Name << endl;
cout << "年龄:" << p.m_Age << endl;
//5.关闭文件
ifs.close();
}
int main() {
test01();
system("pause");
return 0;
}