Bootstrap

C++实现安全性极高的游戏数据存档/读档(附源码)

前言

之前,我们使用传统C语言写了一个游戏的存档、读档程序。

C语言实现安全性极高的游戏存档并读档

但是,需要存储的数据过多时,就会出现这样的情况:

void saveGame(){
    FILE * fp = fopen("...", "w");
    fprintf(fp, "%d %d %d %d %d %d %d %d %d %d...", 
    a, b, c, d, e, f, g, h, i, j...);
}

这么写很容易就会漏掉或使数据错位,导致读写不一致。

因此,我们就可以使用强大的C++文件读写库!

fstream库认识

这一节只是介绍C++的文件读写库,与本文标题无关,已经了解的可以直接跳到后边。

首先来看一段代码:

#include<fstream>
#include<string>

void test(){
    ofstream file;
    file.open("test.txt", ios::out);
//  fstream file("test.txt", ios::out);
    string s = "this is a test";
    file.write(s, sizeof(s));
//  或者写成 file << s << endl; 使用重载的<<操作符
    file.close();
    
    file.open("test.txt", ios::out|ios::in);
}

这里我们先导入fstream头文件。这个头文件主要包含文件的读写。

在第5行,我们定义了一个“类型”为ofstream(文件写入模式)的对象file。以后的所有操作都是在它的基础上完成的。

第6行,我们找到了一个名为test.txt的文件,以ios::out方式打开。当然,也可以像11行一样同时以多个方式打开,中间用“ | ”符号隔开。

(第7行是另一种简便写法,和第5、6行等价)

第8-9行,我们向文件中写入一个字符串s,传进s和它的大小即可。

最后,我们关闭文件。

读的话,用这个:

ifstream in("test.txt", ios::in);
string s;
in.read((char*)&s, sizeof(s));

顺带说一句,文件的读写本质上都是有个文件指针,定义时用in或out是指针指向文件头,

写入时用ios::app把指针移到末尾,也就可以往文件末尾添加数,而不是删掉重写了。

很简单,对不对?

二进制文件读写结构体[正文]

假设我们有如下结构体存放数据:

struct Player{
    int gold, lvl, exp;
    string name;
    ......
}player;

首先,传统C的写入方式容易弄错;而非二进制的C++文件读写则会导致空间的浪费。

因此,我们选择用二进制读写文件。

用ofstream::write()写入文件

ofstream 和 fstream 的 write() 函数用法差不多,其功能是将内存中 buffer 指向的 count 个字节的内容写入文件,基本格式如下:

ofstream & write(char* buffer, int count);

这里为了方便讲解,使用 ostream 声明文件(即文件输出对象)。

ofstream file("game.dat", ios::out | ios::binary)

其中,ios::out表明对文件内容进行写操作,ios::binary说明这是二进制运算。

这样,写入时就可以把整个结构体写进去了

void saveGame(){
    ofstream file("game.dat", ios::out|ios::binary);    //打开文件
    file.write((char*)&player, sizeof(player));         //写入
    file.close();                                       //关闭
}

同样,再写一个函数把它读出来:

void readGame(){
	ifstream file("game.dat", ios::in|ios::binary);     //打开
	if(!file){                                          //判断文件是否不存在
		cout << "error" << endl;                        //不存在就报错
		return ;
	}
	file.read((char*)&player, sizeof(player));          //读入
	file.close();                                       //关闭文件
}

其中,第三行的 ! file 表示判断文件是否不存在,如果不存在为真,报错。

完整程序如下:

#include<bits/stdc++.h>
#include<fstream>
using namespace std;

struct Player{
    int gold, maxHP, HP;
    string name;
}player;
void saveGame(){
    ofstream file("game.dat", ios::out|ios::binary);
    file.write((char*)&player, sizeof(player));
    file.close();
}
void readGame(){
	ifstream file("game.dat", ios::in|ios::binary);
	if(!file){
		cout << "error" << endl;
		return ;
	}
	file.read((char*)&player, sizeof(player));
	file.close();
}

int main()
{
	player.gold = 0;
	player.HP = 100;
	player.maxHP = 100;
	player.name = "a name";
	saveGame();
	cout << player.gold << ' ' << player.HP << ' ' << player.maxHP << endl;
	cout << player.name << endl;
	return 0;
}

执行代码,运行结果为:

0 100 100
a name

而文件中的内容在作者的环境下是这样的:

    d   d       ??  

所以,不用担心普通玩家恶意篡改文件内容导致破坏游戏平衡。

那这篇文章就到这里了,最后感谢大家的阅读,我们下次再见!

【题外话】最近一年多没更新了,可能这篇文章写得也不咋的,以后尽量保持月更,

希望大家谅解、支持。你们的赞是对我最大的鼓励,谢谢!

;