C++文件操作

写入文本文件

  • 在C++中,文件操作属于技术的应用,不是基本语法。
  • 数据持久化的两种方式:文件和数据库。
    在这里插入图片描述
    文本文件一般以行的形式组织数据。
    包含头文件:#include <fstream>
    类: ofstream (output file stream)
    示例:
#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>
using namespace std;
int main() {
	ofstream fout;//创建文件输出流文件
	fout.open("test.txt");//打开文件,如果不存在就创建他,如果存在,则截断其内容

	//向问价中写入数据
	fout << "西施|19|及其漂亮\n";
	fout << "冰冰|22|漂亮\n";
	fout << "幂幂|25|一般\n";
	
	fout.close();//关闭文件,fout对象失效前会自动调用close()。
	
	cout << "操作文件完成.\n";
}

在这里插入图片描述
对于open()成员函数的参数,可以用C风格的字符串,也可以用string.

ofstream fout;//创建文件输出流文件
//fout.open("test.txt");//打开文件,如果不存在就创建他,如果存在,则截断其内容

string filename = "test.txt";
//char filename[]="test.txt";
fout.open(filename);

如果要指定目录的话:

string filename="D:\\data\\txt\\test.txt";

一般文件名要全路径,书写的方法如下:

  1. "D:\data\txt\test.txt"错误。
  2. R"(D:\data\txt\test.txt)”原始字面量,C++11标准。
  3. "D:\\data\\txt\\test.txt"转义字符。
  4. "D:/tata/txt/test.txt"把斜线反着写。
  5. "/data/txt/test.txt"Linux系统采用的方法。

创建文件输出流对象,打开文件,如果文件不存在,则创建它。

ios::out 缺省值:会截断文件内容。
ios::trunc 截断文件内容。
ios::app//不截断文件内容,只在文件未尾追加文件。
ofstream fout(filename);
ofstream fout(filename, ios::out);
ofstream fout(filename, ios:trunc);
ofstream fout(filename, ios:app);
fout.open(filename);

对于,前三个都是清空文件,然后再写,也就是覆盖写。 ios:app则是继续在他的后面写也就是追加写。
然后这个就是追加写的代码:

#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>
using namespace std;
int main() {
	ofstream fout;//创建文件输出流文件
	//fout.open("test.txt");//打开文件,如果不存在就创建他,如果存在,则截断其内容

	string filename = "test.txt";
	//char filename[]="test.txt";

	//创建文件输出流对象,打开文件,如果文件不存在,则创建它。
	// ios::out 缺省值:会截断文件内容。
	// ios::trunc 截断文件内容。
	// ios::app//不截断文件内容,只在文件未尾追加文件。
	//ofstream fout(filename);
	//ofstream fout(filename, ios::out);
	//ofstream fout(filename, ios:trunc);
	//ofstream fout(filename, ios:app);
	//fout.open(filename);

	ofstream fout;
	fout.open(filename, ios::app);

	//判断打开文件是否成功
	//失败的原因主要有:1)目录不存在;2)磁盘空间已满;3)没有权限,Linux平台下很常见。
	if (fout.is_open() == false) {
		cout << "打开文件" << filename << "失败.\n";
		return 0;
	}

	//向文件中写入数据
	fout << "西施|19|及其漂亮\n";
	fout << "冰冰|22|漂亮\n";
	fout << "幂幂|25|一般\n";
	
	fout.close();//关闭文件,fout对象失效前会自动调用close()。
	
	cout << "操作文件完成.\n";
}

读取文件内容

这里有三种方法:

  1. 第一种getline(fin, buffer)
//第一种方法
string buffer;//用于存放从文件中读取的内容
//读取文件内容的代码
//文本文件一般以行的方式组织数据
while (getline(fin, buffer)) {
	cout << buffer<<endl;
}
  1. 第二种fin.getline(buffer, 100)第二个参数是最多读取内容的字节数
//第二种方法
char buffer[101];
//注意:如果采用ifstream.getline(),一定要保证缓冲区足够大
while (fin.getline(buffer, 100)) {//第二个参数是最多读取内容的字节数
	cout << buffer << endl;
}
  1. 第三个fin >> buffer
string buffer;
while (fin >> buffer) {
	cout << buffer << endl;
} 
#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>//ifstream 类需要包含的头文件
#include<string>
using namespace std;
int main() {
	
	string filename = "test.txt";
	//char filename[]="test.txt";

	//创建文件输入流对象,打开文件,如果文件不存在,则创建它。
	// ios::in 缺省值.
	//ifstream fin(filename);
	//ifstream fin(filename, ios::in);

	ifstream fin;
	fin.open(filename, ios::in);

	//判断打开文件是否成功
	//失败的原因主要有:1)目录不存在;2)文件不存在;3)没有权限,Linux平台下很常见。
	if (fin.is_open() == false) {
		cout << "打开文件" << filename << "失败.\n";
		return 0;
	}


	第一种方法
	//string buffer;//用于存放从文件中读取的内容
	读取文件内容的代码
	文本文件一般以行的方式组织数据
	//while (getline(fin, buffer)) {
	//	cout << buffer<<endl;
	//}

	第二种方法
	//char buffer[101];
	注意:如果采用ifstream.getline(),一定要保证缓冲区足够大
	//while (fin.getline(buffer, 100)) {//第二个参数是最多读取内容的字节数
	//	cout << buffer << endl;
	//}
	
	//第三种方法
	string buffer;
	while (fin >> buffer) {
		cout << buffer << endl;
	}
	
	fin.close();//关闭文件,fout对象失效前会自动调用close()。
	
	cout << "操作文件完成.\n";
}

写入二进制文件

首先我们先看看数据在内存中的分配
在这里插入图片描述
对于第一个string类型的。每个字节存放一个字符,字符在内存中存放的是ascii码,不是符号。

对于第二个int类型的。如果是整数变量存放,那么它就是二进制数据,或者二进制格式。

文件操作

  • 写文件:把内存中的数据转移到磁盘文件中。
  • 读文件:把磁盘文件中的数据转移到内存中。
  • 内存和硬盘都是存储设备,本质上没有区别。

文本文件和二进制文件

  • 文本文件:存放的是字符串,以行的方式组织数据,每个字节都是有意义的符号。
  • 二进制文件:存放的不一定是字符串,以数据类型组织数据,内容要作为一个整体来考虑,单个字节没有意义。

二进制文件以数据块的形式组织数据,把内存中的数据直接写入文件。
包含头文件:#include <fstream>
类:ofstream (output file stream)
ofstream打开文件的模式(方式):
对于ofstream,不管用哪种模式打开文件,如果文件不存在,都会创建文件。

ios:out         缺省值:会截断文件内容。
ios:trunc      截断文件内容。(truncate)
ios:app        不截断文件内容,只在文件未尾追加文件。(append)
ios::binary     以二进制的方式打开文件

文本和二进制方式的区别:

  1. 在windows平台下,文本文件的换行标志是\r\n
  2. 在windows平台下,如果以文本方式打开文件,写入数据的时候,系统会将"\n"转换成"\r\n";读取数据的时候,系统会将"\r\n"转换成"\n"。如果以二进制方式打开文件,写和读都不会进行转换。

对于他和其他不一样的就是,第一点就是打开的时候要用二进制fout.open(filename,ios::app | ios::binary);
然后第二点就是写入的时候就是fout.write()

#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>//ifstream 类需要包含的头文件
#include<string>
using namespace std;
int main() {
	
	//文件名一般用全路径,书写的方法如下
	//1. "D:\data\txt\test.dat"     错误。
	//2. R"(D:\data\txt\test.dat)"  原始字面量,C++11标准。
	//3. "D:\\data\\txt\\test.dat"  转义字符。
	//4. "D:/tata/txt/test.dat"     把斜线反着写。 
	//5. "/data/txt/test.dat"       Linux系统采用的方法。
	string filename = R"(test.dat)";
	//char filename[] = R"(test.dat)";
	//创建文件输出流对象,打开文件,如果文件不存在,则创建它
	
	//ios::out     缺省值:会截断文件内容
	//ios::trunc   截断文件内容(truncate)
	//ios::app     不截断文件内容,只要文件末尾追加文件(append)
	//ios::binary 以二进制方式打开文件
	//ofstream fout(filename,ios::binary);
	//ofstream fout(filename,ios::out | ios::binary);
	//ofstream fout(filename,ios::trunc | ios::binary);
	//ofstream fout(filename,ios::app | ios::binary);
	
	ofstream fout;
	fout.open(filename, ios::app | ios::binary);//竖线就是按位或运算

	//判断打开文件是否成功
	//失败的原因主要有:1)目录不存在;2)磁盘空间已满;3)没有权限,Linux平台下很常见。
	if (fout.is_open() == false) {
		cout << "打开文件" << filename << "失败.\n";
		return 0;
	}
	//向文件中写入数据
	struct st_girl {
		char name[301];//姓名
		int no;//编号
		char memo[301];//备注
		double weight;//体重
	}girl;

	girl = {"西施",3,"中国历史第一美女。",45.8};
	fout.write((const char*)&girl, sizeof(st_girl));//写入第一块数据。
	girl ={"冰冰",8,"也是个大美女哦。",55.2};
	fout.write((const char*)&girl,sizeof(st_girl));//写入第二块数据。


	fout.close();
	cout << "操作文件完成" << endl;

}

在这里插入图片描述

读取二进制文件

二进制文件的格式

  • 二进制文件的格式多样,由业务需求决定。
  • 程序员自定义的二进制文件格式,只有程序员自己才知道。
  • 通用的二进制文件格式: mp3(音乐)、mp4(视频)、bmp(位图)、jpg(图片)、png(图片)

文本文件VS二进制文件

  • 文件文件:由可显示的字符组成,方便阅读(解码),占用的空间比较多。
  • 二进制文件:由比特0和1组成,组织数据的格式与文件用途有关,不方便阅读(解码)。为了节省存储空间,还可能采用压缩技术。为了保证数据安全,也可能采用加密技术。

包含头文件#include<fstream>
类:ifstream
ifstream 打开文件的模式(方式):
对于ifstream,如果文件不存在,则打开文件失败

ios::in     缺省值:会截断文件内容
ios::binary 以二进制方式打开文件
ifstream fout(filename,ios::binary);
ifstream fout(filename,ios::in | ios::binary);

ifstream fin;
fin.open(filename, ios::in | ios::binary);//竖线就是按位或运算

#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>//ifstream 类需要包含的头文件
#include<string>
using namespace std;
int main() {
	
	//文件名一般用全路径,书写的方法如下
	//1. "D:\data\txt\test.dat"     错误。
	//2. R"(D:\data\txt\test.dat)"  原始字面量,C++11标准。
	//3. "D:\\data\\txt\\test.dat"  转义字符。
	//4. "D:/tata/txt/test.dat"     把斜线反着写。 
	//5. "/data/txt/test.dat"       Linux系统采用的方法。
	string filename = R"(test.dat)";
	//char filename[] = R"(test.dat)";
	//创建文件输出流对象,打开文件,如果文件不存在,则创建它
	
	//ios::in     缺省值:会截断文件内容
	//ios::binary 以二进制方式打开文件
	//ifstream fout(filename,ios::binary);
	//ifstream fout(filename,ios::in | ios::binary);
	
	ifstream fin;
	fin.open(filename, ios::in | ios::binary);//竖线就是按位或运算

	//判断打开文件是否成功
	//失败的原因主要有:1)目录不存在;2)磁盘空间已满;3)没有权限,Linux平台下很常见。
	if (fin.is_open() == false) {
		cout << "打开文件" << filename << "失败.\n";
		return 0;
	}
	//向文件中写入数据
	struct st_girl {
		char name[301];//姓名
		int no;//编号
		char memo[301];//备注
		double weight;//体重
	}girl;

	while (fin.read((char*)&girl, sizeof(girl))) {
		cout << "name=" << girl.name << ",no=" << girl.no << ",memo=" << girl.memo << endl;
	}


	fin.close();
	cout << "操作文件完成" << endl;

}

文件操作的一些细节

  1. 在windows 平台下,文本文件的换行标志是"\r\n". (也就是多两个字节)
  2. 在linux平台下,文本文件的换行标志是"\n"
  3. 在windows平台下,如果以文本方式打开文件,写入数据的时候,系统会将"\n"转换成
    "\r\n";读取数据的时候,系统会将"\r\n"转换成"\n"。如果以二进制方式打开文件,写和读都不会进行转换。
  4. 在Linux平台下,以文本或二进制方式打开文本文件,系统不会做任何转换。
  5. 以文本方式读取文件的时候,遇到换行符停止,读入的内容中没有换行符;以二制方式读取文件的时候,遇到换行符不会停止,读入的内容中包括换行符(换行符被视为数据)。
  6. 在实际开发中,从兼容和语义考虑,一般: a)以文本模式打开文本文件,用行的方法操作它;b)以二进制模式打开二进制文件;用数据块的方法操作它;c)以二进制模式打开文本文件,用数据块的方法操作它(不用行hang的方法),这种情况表示不关心数据的内容;d)不要以文本模式打开二进制文件,也不要用行的方法操作二进制文件,可能会破坏二进制数据文件的格式,也没有必要。(因为二进制文件中的某字节的取值可能是换行符,但它的意义并不是换行,可能是整数n个字节中的某个字节)

fstream类

之前讲了ofsteam类,还有ifstream类。
下面讲一下fstream类。
fstream类既可以读文本/二进制文件,也可以写文本/二进制文件。
fstream类的缺省模式是ios:in | ios::out
普遍的做法是:

  1. 如果只想写入数据,用ofstream;如果只想读取数据,用ifstream;如果想写和读数据,用fstream,这种情况不多见。不同的类体现不同的语义。
    也就是对于上面的代码将ifstream或者ofstream改成fstream。这种情况不多见。不同的类体现不同的语义。
  2. 在Linux平台下,文件的写和读有严格的权限控制。(需要的权限越少越好)

文件操作-随机存取

文件位置指针

        对文件进行读/写操作时,文件的位置指针指向当前文件读/写的位置。
        很多资料中用“文件读指针的位置”和“文件写指针的位置”,容易误导人。不管用哪个类操作文件,文件的位置指针只有一个。

  1. 获取文件位置指针
    ofstream类的成员函数是tellp()ifstream类的成员函数是tellg(),fstream类两个都有,效果相同
std::streampos tellp();
std::streampos tellg();

例如:

#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>
using namespace std;
int main() {
	//fout.open("test.txt");//打开文件,如果不存在就创建他,如果存在,则截断其内容

	string filename = "test.txt";
	//char filename[]="test.txt";

	//创建文件输出流对象,打开文件,如果文件不存在,则创建它。
	// ios::out 缺省值:会截断文件内容。
	// ios::trunc 截断文件内容。
	// ios::app//不截断文件内容,只在文件未尾追加文件。
	//ofstream fout(filename);
	//ofstream fout(filename, ios::out);
	//ofstream fout(filename, ios:trunc);
	//ofstream fout(filename, ios:app);
	//fout.open(filename);

	ofstream fout;
	fout.open(filename, ios::out);

	//判断打开文件是否成功
	//失败的原因主要有:1)目录不存在;2)磁盘空间已满;3)没有权限,Linux平台下很常见。
	if (fout.is_open() == false) {
		cout << "打开文件" << filename << "失败.\n";
		return 0;
	}

	//向文件中写入数据
	cout << "位置:" << fout.tellp()<<endl;
	fout << "西施|19|及其漂亮\n";
	cout << "位置:" << fout.tellp() << endl;
	fout << "冰冰|22|漂亮\n";
	cout << "位置:" << fout.tellp() << endl;
	fout << "幂幂|25|一般\n";
	cout << "位置:" << fout.tellp() << endl;


	fout.close();//关闭文件,fout对象失效前会自动调用close()。

	cout << "操作文件完成.\n";
}

对于这个结果:

他的位置指针是自己变化的,不需要我们进行调整。
2. 移动文件位置指针
ofstream类的函数是seekp(); ifstream类的函数是seekg(); fstream类两个都有,效果相同。
方法一:

std:.istream & seekg(std:streampos_Pos);
fin.seekg(128);//把文件指针移到第128字节。fin.seekp(128);//把文件指针移到第128字节。-fin.seekp(ios:beg)//把文件指针移动文件的开始。fin.seekp(ios:end)// 把文件指针移动文件的结尾。

方法二:

std:istream & seekg(stdstreamoff_Off,stdios:seekdir _Way);
在ios 中定义的枚举类型:
enum seek_dir {beg, cur, end;//beg-文件的起始位置;cur-文件的当前位置;end-文件的结尾位置。
fin.seekg(30,ios:beg);//从文件开始的位置往后移30字节。fin.seekg(-5,ios::cur);//从当前位置往前移5字节。
fin.seekg(8,ios:.cur);//从当前位置往后移8字节。
fin.seekg(-10,ios:end);//从文件结尾的位置往前移10字节。 
#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>//ifstream 类需要包含的头文件
#include<string>
using namespace std;
int main() {

	string filename = "test.txt";
	//char filename[]="test.txt";

	//创建文件输入流对象,打开文件,如果文件不存在,则创建它。
	// ios::in 缺省值.
	//ifstream fin(filename);
	//ifstream fin(filename, ios::in);

	fstream fs;
	fs.open(filename, ios::in | ios::out);

	//判断打开文件是否成功
	//失败的原因主要有:1)目录不存在;2)文件不存在;3)没有权限,Linux平台下很常见。
	if (fs.is_open() == false) {
		cout << "打开文件" << filename << "失败.\n";
		return 0;
	}
	fs.seekg(22);//把文件位置移动到第22字节处。
	string buffer;
	while (fs >> buffer) {
		cout << buffer << endl;
	}

	fs.close();//关闭文件,fout对象失效前会自动调用close()。

	cout << "操作文件完成.\n";
}

缓冲区和流状态

在这里插入图片描述
写文件的时候,就是先向缓冲区中写数据,如果缓冲区满了,然后在向磁盘中写入。
读数据的时候,就是系统先把更多的数据从磁盘文件中读取出来,放到缓冲区中。
总的来说,缓冲区可以减少磁盘I/O的次数,提高读和写的效率。

文件缓冲区

文件缓冲区(缓存)是系统预留的内存空间,用于存放输入或输出的数据。
根据输出和输入流,分为输出缓冲区和输入缓冲区。
注意,在C++中,每打开一个文件,系统就会为它分配缓冲区。不同的流,缓冲区是独立的。程序员不用关心输入缓冲区,只关心输出缓冲区就行了。
在缺省模式下,输出缓冲区中的数据满了才把数据写入磁盘,但是,这种模式不一定能满足业务的需求。
输出缓冲区的操作:

  1. flush()成员函数
    直接刷新缓冲区。
  2. endl
    换行,然后刷新缓冲区
  3. unitbuf
    fout<<unitbuf;
    设置fout输出流,在每次操作之后都进行刷新缓冲区。
  4. nounitbuf
    fout<<nounitbuf;
    设置fout输出流,让fout回到缺省的缓冲方式

状态流

流状态有三个:eofbitbadbitfailbit,取值:1-设置;或0-清除。
当三个流状成都为0时,表示一切顺利,good()成员函数返回true。

  1. eofbit
    当输入流操作到达文件末尾时,将设置eofbit。
    eof()成员函数检查流是否设置了eofbit。
  2. badbit
    无法诊断的失败破坏流时,将设置badbit。(例如:对输入流进行写入;磁盘没有剩余空间)。bad()成员函数检查流是否设置了badbit。
  3. failbit
    当输入流操作未能读取预期的字符时,将设置failbit(非致命错误,可挽回,一般是软件错误,例如:想读取一个整数,但内容是一个字符串;文件到了未尾)IО失败也可能设置 failbit。
    fail()成员函数检查流是否设置了failbit。
  4. clear()成员函数清理流状态。
  5. setstate()成员函数重置流状态。
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值