目录
- 文件操作
- C++中的文件操作时基于面向对象的
- C++中文件类型分为两种:
- 操作文件的三大类(这些类都属于标准模板库):
- 1 文本文件
- 1.1 写文件
- 写文件步骤如下:
- 文件打开方式:
- 1.2 读文件
- 读取文件数据的四种方式
- 按照喜好记前三个中的一个就行
- 综合
- 2 二进制文件(不仅可以操作内置数据类型还可以操作自定义数据类型)
- 注意打开方式要指定为 ==ios::binary==
- 2.1 写文件
- 注意:对文件操作时,字符串最好使用C语言风格的字符串(也就是字符数组)因为wirte()和read函数()都包含参数char *,用string会引发错误
- 2.2 读文件
- 步骤
- 注意事项:
文件操作
视频链接
C++中的文件操作时基于面向对象的
程序运行时产生的数据都属于临时数据,程序一旦运行结束都会被释放
通过文件可以将数据持久化
C++中对文件操作需要包含头文件 < fstream >
C++中文件类型分为两种:
- 文本文件 - 文件以文本的ASCII码形式存储在计算机中
- 二进制文件 - 文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们
操作文件的三大类(这些类都属于标准模板库):
- ofstream(output):写入文件操作
- ifstream(input): 读取数据操作
- fstream : 读写操作。一般使用这个类进行文本操作
1 文本文件
1.1 写文件
写文件步骤如下:
-
包含头文件
#include <fstream>
-
创建流对象
ofstream ofs;
-
打开文件
ofs.open(“文件路径”,打开方式);
文件路径可以直接写个文件名,因为如果不指定路径的话,他会默认在当前项目路径下。 -
写数据
ofs << “写入的数据”;
类似于cout<<“…”; cout就是往屏幕上输出,而ofs就是往文件里输出 -
关闭文件,这一步很重要而且容易遗漏
ofs.close();
文件打开方式:
#include<iostream>
using namespace std;
#include<string>
// 1.包含头文件 fstream
#include<fstream>
// 文本文件 写文件
void test01() {// 1.包含头文件// 2.创建流对象ofstream ofs;// 3.指定打开的方式//文件名为test.txtofs.open("test.txt", ios::out);// 4.写内容ofs << "姓名:张三" << endl << "年龄:19" << endl << "性别:男" << endl;// 5.关闭文件ofs.close();}
int main() {test01();cin.get();return 0;}
总结:
- 文件操作必须包含头文件 fstream
- 读文件可以利用 ofstream ,或者fstream类
- 打开文件时候需要指定操作文件的路径,以及打开方式
- 利用<<可以向文件中写数据
- 操作完毕,要关闭文件
1.2 读文件
读文件与写文件步骤相似,但是读取方式相对于比较多
读文件步骤如下:
-
包含头文件
#include <fstream>
-
创建流对象
ifstream ifs;
-
打开文件并判断文件是否打开成功
ifs.open(“文件路径”,打开方式);
-
读数据
四种方式读取
-
关闭文件,记住别忘了要关闭文件
ifs.close();
判断文件是否打开成功(其实也就是判断有没有这个文件):
if (!ifs.is_open()){cout << "文件打开失败" << endl;return;}
if_open()是系统自带的布尔类型函数,打开成功返回1
打开失败返回0(这个函数是判断文件是否存在的)
读取文件数据的四种方式
按照喜好记前三个中的一个就行
- 第一种方式:把文件内容全部放在字符数组中
//第一种方式char buf[1024] = { 0 };//首先初始化字符数组while (ifs >> buf)// ifs右移运算符,他会读取数据并放到buf数组中,当数据全部读完后,返回一个false,while循环也就结束了{cout << buf << endl;}
- 第二种方式:使用ifs.getline()函数
ifs.getline(char *str,count)中有两个参数;
char *str:表示我们要把读取的数据放到哪个地方,一般是个数组
count:所占的空间
//第二种char buf[1024] = { 0 };while (ifs.getline(buf,sizeof(buf))){cout << buf << endl;}
- 第三种方式:把内容放到string字符串中
包含头文件include
然后使用函数getline(输入流对象,准备好的字符串)
//第三种string buf;while (getline(ifs, buf)){cout << buf << endl;}
- 不太推荐的第四种方式:他会将文件中的所有数据一个一个地读出来,放到字符C里边。效率太差
ifs.get()每次只读一个字符。EOF代表末尾的意思
// 第四种char c;while ((c = ifs.get()) != EOF){cout << c;}
综合
#include<iostream>
using namespace std;
//1. 包含头文件
#include<fstream>
#include<string>void test01()
{ // 2. 创建流对象 ifstream ifs;//3. 打开文件并判断文件是否打开成功ifs.open("test.txt", ios::in);if (!ifs.is_open()){cout << "文件打开失败" << endl;return;}// 4. 读数据// 四种方式//第一种方式//char buf[1024] = { 0 };//while (ifs >> buf)//{// cout << buf << endl;//}//第二种//char buf[1024] = { 0 };//while (ifs.getline(buf,sizeof(buf)))//{// cout << buf << endl;//}//第三种string buf;while (getline(ifs, buf)){cout << buf << endl;}// 第四种//char c;//while ((c = ifs.get()) != EOF)//{//cout << c;//}// 5. 关闭文件ifs.close();}int main() {test01();system("pause");return 0;
}
2 二进制文件(不仅可以操作内置数据类型还可以操作自定义数据类型)
以二进制的方式对文件进行读写操作
注意打开方式要指定为 ios::binary
2.1 写文件
二进制方式写文件主要利用流对象调用成员函数write
函数原型 :ostream& write(const char * buffer,int len);
参数解释:参数一:字符指针常量buffer(也可以理解为就是一段地址(指针就是地址),不过要把它强制转换成const char * ) 。 buffer指向内存中一段存储空间。len是读写的字节数
数组名就可以直接作为参数一,当传数组给一个函数时,数组类型自动转换为指针类型,传的实际是数组元素首地址。
建议看的文章1:将地址强制转换为指针
建议看的文章2指针的强制类型转换
注意:对文件操作时,字符串最好使用C语言风格的字符串(也就是字符数组)因为wirte()和read函数()都包含参数char *,用string会引发错误
#include<iostream>
using namespace std;#include <fstream>
#include <string>class Person
{
public:char m_Name[64];int m_Age;
};//二进制文件 写文件
void test01()
{//1、包含头文件//2、创建输出流对象ofstream ofs("person.txt", ios::out | ios::binary|ios::trunc);//3、打开文件//ofs.open("person.txt", ios::out | ios::binary);int a = 55;int d[20];for (int i = 0; i < 20; i++) {d[i] = i;}Person p = { "张三" , 18 };char c[15] = { "Hello,World!" };//4、写文件ofs.write((const char*)&a, sizeof(a));ofs.write((const char*)d, sizeof(c));ofs.write((const char*)&p, sizeof(p));ofs.write((const char*)c, sizeof(c));//5、关闭文件ofs.close();
}int main() {test01();system("pause");return 0;
}
二进制文件打开是乱码
2.2 读文件
二进制方式读文件主要利用流对象调用成员函数read
函数原型:istream& read(char *buffer,int len);
参数解释:参数一:字符指针buffer(也可以理解为就是一段地址(指针就是地址),不过要把它强制转换成 char * ) 。它指向内存中一段存储空间。len是读写的字节数
数组名可以直接作为参数一,当传数组给一个函数时,数组类型自动转换为指针类型,传的实际是数组元素首地址。
步骤
- 包含头文件
- 创建流对象
- 打开文件并判断文件是否打开成功
- 将二进制数据转换为可读数据
- 打印转换后的可读数据
- 关闭文件
#include<iostream>
using namespace std;
// 1.包含头文件
#include <fstream>
#include <string>class Person
{
public:char m_Name[64];int m_Age;
};void test01()
{// 2.创建流对象的同时打开文件ifstream ifs("person.txt", ios::in | ios::binary);// 3.判断文件是否打开成功if (!ifs.is_open()){cout << "文件打开失败" << endl;}Person p;// 4.将二进制数据转换为可读数据// 这一步不能将数据读出到屏幕上,这一步的作用只是把二进制数据转换为可读数据int d;int z[20];char c[15];ifs.read((char*)&d, sizeof(d));ifs.read((char*)z, sizeof(z));ifs.read((char*)&p, sizeof(p));ifs.read((char*)c, sizeof(c));// 5.打印转换后的可读数据// 用cout即可读出数据cout << "d=" << d << endl;cout << "姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl;for (int i = 0; i < 20; i++) {cout << z[i] << endl;}for (int i = 0; i < 15; i++) {cout << c[i];}cout << endl;// 6.关闭文件ifs.close();}int main() {test01();system("pause");return 0;
}
注意事项:
- 把什么数据类型写入文件,查看文件时就要用相应的数据类型来接受。
比如用write函数写入一个整形数组:
int c[20];ofs.write((const char*)&c, sizeof(c));
那么read函数接受时也应用整形数组来接受:
int z[20];
ifs.read((char*)z, sizeof(z));
- 用write函数按某一顺序写入了多个数据类型时,read函数查看时也应与写入时的顺序一样
比如按下列顺序用write函数写入了以下四个数据类型:
int a = 55;int d[20];Person p = { "张三" , 18 };char c[15] = { "Hello,World!" };//4、按下列顺序写入文件ofs.write((const char*)&a, sizeof(a));ofs.write((const char*)d, sizeof(c));ofs.write((const char*)&p, sizeof(p));ofs.write((const char*)c, sizeof(c));
read函数查看时也得与写入时的顺序相同:
int d;int z[20];char c1[15];Person p1;
// 注意各个read函数的顺序ifs.read((char*)&d, sizeof(d));ifs.read((char*)z, sizeof(z));ifs.read((char*)&p1, sizeof(p1));ifs.read((char*)c1, sizeof(c1));
不能写成下面这样:
int d;int z[20];char c1[15];Person p1;ifs.read((char*)&d, sizeof(d));ifs.read((char*)c1, sizeof(c1));ifs.read((char*)z, sizeof(z));ifs.read((char*)&p1, sizeof(p1));