c++存取dat數據

      衆所周知,dat是一個類似加密的二進制格式文件,很多人喜歡將遊戲數據保存在dat文件中,只有知道你的存放格式,才能夠將數據破解出來,因而研究了dat文件的存取方式。其實就是c++文件的操作,只不過是在取的時候需要按照自己存放的格式獲取出來。

本文將實現將結構體數據保存到dat文件,並且將dat文件讀取回來。

1.struct結構體的格式數據

      首先定義一個結構體,用以存放存入dat文件的數據,同時,再取的時候按照結構體的格式進行獲取操作:

#pragma once
#ifndef _STRUCT_H_
#define _STRUCT_H_

#include<vector>
#include <iostream>
#include <string>
using namespace std;;
#define MaxSize 10
//設置結構體的邊界對齊爲1個字節,對於結構體中的char數組,如果不滿4的倍數字節,會默認補齊,聲明之後數據在內存中是連續存儲的。
#pragma pack(1) 
typedef struct _TEST_DAT
{
	int type;
	char name[MaxSize];
	int age;
}TESTDAT;

#pragma pack()

#endif 
這時的結構體內存結構是對齊的。


2.TxtToFile存取dat文件

         先說存,首先初始化一個結構體,其次將該結構體數據依次保存到指定名字的dat文件中,如下:

TxtToFile.h

#pragma once
#ifndef _TXT_TO_FILE_H_
#define _TXT_TO_FILE_H_
#include<vector>
#include <iostream>
#include <fstream>
#include <string>
#include "Struct.h"
#include <stdio.h>
using namespace std;
class TxtToFile
{
public:
	TxtToFile();
	~TxtToFile();
	//外調函數,保存到dat文件
	bool  SaveToDat(string _datPath);
private:
	TESTDAT	m_dat;
	fstream	m_datstream;
	vector<TESTDAT>	m_getdat;

private:
	// 把基本的Number類型寫入文件流中
	template<class T>
	bool Write(T value)
	{
		//re
		m_datstream.write(reinterpret_cast<char *>(&value), sizeof(T));
		return true;
	}
	//把字符串寫入文件流
	void  WriteString(string _str, int	_count);
};
#endif
TxtToFile.cpp
#include "stdafx.h"
#include "TxtToFile.h"
#include <sstream>

TxtToFile::TxtToFile()
{
	m_dat = TESTDAT{
		0,
		"dasdasd",
		1
	};
	
}


TxtToFile::~TxtToFile()
{
}
bool TxtToFile::SaveToDat(string _datPath)
{
	if (_datPath.size() == 0)
	{
		return false;
	}
	m_datstream.open(_datPath, fstream::out | fstream::binary);//以二進制的形式打開文件
	if (!m_datstream.is_open())
	{
		cout << "open" << _datPath << "Failed" << endl;
		m_datstream.close();
		return false;
	}
	Write(m_dat.type);//存入數據
	WriteString(m_dat.name, MaxSize);
	Write(m_dat.age);
	//Write(m_dat);
	cout << "Successed" << endl;
	m_datstream.close();
	return true;
}
void TxtToFile::WriteString(string _str, int _count)
{
	if (_str.length()>=_count)
	{
		cout << "write string error!" << endl;
		return;
	}
	m_datstream << _str;
	int len = _count - _str.length();
	while (len--)
	{
		m_datstream << '\0';
	}
}



         這個時候,已經把數據存入到dat文件中,接下來就是取數據了,如下:

首先在頭文件中加兩個函數:


	//從dat文件讀取數據
	bool GetFromDat(string _datPath);
	__int64 getFileSize(const char *filename);

cpp:
bool TxtToFile::GetFromDat(string _datPath)
{
	if (_datPath.size()==0)
	{
		return false;
	}
	
	__int64 scount = 0;
	__int64 stuctsize = sizeof(TESTDAT);
	TESTDAT testdat;
	__int64 filesize = getFileSize(_datPath.c_str());
	if (filesize==0|| filesize<stuctsize ||(filesize%stuctsize)!=0)
	{
		return false;
	}
	scount = filesize / stuctsize;

	FILE *inStream = NULL;
	const char* name = _datPath.c_str();
	inStream = fopen(name, "rb");
	if (inStream == NULL) return false;
	for (int i = 0; i < scount; i++)
	{
		//size_t fread(void *ptr, size_t size, size_t n, FILE *stream);
		//參數ptr是保存讀取的數據,void*的指針可用任何類型的指針來替換,如char*、int *等等來替換;
		//size是每塊的字節數;n是讀取的塊數,如果成功,返回實際讀取的塊數(不是字節數),本函數一般用於二進制模式打開的文件中。
		fread(&testdat, stuctsize, 1, inStream);
		/*if (testdat.duration < 0)
		{
			fclose(inStream);
			return false;
		}*/
		m_getdat.push_back(testdat);
	}

	fclose(inStream);

	return true;
}

__int64 TxtToFile::getFileSize(const char *filename)
{
	__int64 size = 0;
	/*FILE *fp = fopen(filename, "rb");
	if (!fp)
	{
		return 0;
	}

	fseek(fp, 0, SEEK_END);
	size = ftell(fp);
	fseek(fp, 0, SEEK_SET);

	fclose(fp);*/
	fstream instreams;
	instreams.open(filename, ios::_Nocreate);
	if (!instreams.is_open())
	{
		return 0;
	}
	instreams.seekg(0, ios::end);
	size = instreams.tellg();
	instreams.close();
	return size;
}
讀的時候用的是C語言的,因爲映射一下就是結構體了,而且存的時候沒有存空格\n\t之類的分隔符,所以用getline不好取。

3.測試樣例

main函數:

// DatTxt.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"
#include "TxtToFile.h"

int _tmain(int argc, _TCHAR* argv[])
{
	TxtToFile ttofile;
	ttofile.SaveToDat("Test.Dat");
	ttofile.GetFromDat("Test.Dat");
	return 0;
}


運行視圖:
成功,並且能在目錄下找到dat文件,如果要看取出來的數據,那麼需要加斷點查看咯

Over
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章