精確的概括是:
按名稱從資源文件里面讀和寫二進制raw數據(raw在文件里面是按zlib壓縮的形式存儲的)
這樣我就可以把一些文件資源用對應的api讀入到內存的buffer中去,然后通過我的資源庫壓縮buffer再寫入到資源文件里面去,下次真正調用的時候讀出來解壓還原到內存的buffer里面去使用。
下面要做的事情就是把游戲里面所有的資源文件都打包了。
只是目前還沒有加上加密的算法
//看一段測試代碼
void testFilestream()
{
FileStream filestream;
filestream.Open("aaa.bin", "r+");
char *p=0;
DWORD ln = 0;
char *src = "hello,a big boy";
filestream.Write("xxx.xxx", src, strlen(src));
filestream.Read("xxx.xxx", (void **)&p, ln);
printf("%s :%d\r\n", p, ln);
DELS(p);
filestream.Close();
}
結果:
hello,a big boy :15
請按任意鍵繼續. . .
源碼如下:
/************************************************************************/
/* 按命名從資源文件里面讀和寫raw數據(raw在文件里面是按zlib壓縮的形式存儲的)
/************************************************************************/
#pragma once
#ifndef FILESTREAM_H
#define FILESTREAM_H
#include <stdio.h>
#include <WTypes.h>
#include <string>
#include <assert.h>
#include "../include/zlib.h"
#pragma comment(lib,"../lib/zdll.lib")
namespace LK3D
{
class FileStream;
//////////////////////////////////////////////////////////////////////////////////////
// 文件或數據流(不支持同時讀寫多個數據區,只能一次對FileStream的一個數據區進行讀寫操作)
class FileDataStreamBuffer
{
private:
DWORD zipbuflen; //zip raw buffer len
void * zipbuf; //zip raw buffer 壓縮字節流
//按照buflen重新分配空間
void realloc();
DWORD srcbuflen; //source raw buffer len
std::string dataname; //該數據流的名字
public:
DWORD GetSrcBufLen();
//構造
FileDataStreamBuffer(const char *dname);
//析構
~FileDataStreamBuffer();
//寫字節,寫之前一定要設定dataname
DWORD WriteBytes(const void *from,DWORD len);
//讀字節,寫之前一定要設定dataname
DWORD ReadBytes(void *to);
//debug
void DumpBuffer();
DWORD GetLen() const; //總長度,是計算出來的
bool operator ==(const FileDataStreamBuffer &other) const;
friend class FileStream;
};
class FileStream
{
FILE *pFile;
private:
//寫文件包,寫之前一定要設定filebuf.dataname
DWORD Write(FileDataStreamBuffer& filebuf);
//讀文件包,讀之前一定要設定filebuf.dataname
DWORD Read(FileDataStreamBuffer& filebuf);
public:
FileStream(void);
~FileStream(void);
//打開一個文檔
DWORD Open(const char* archive,const char *mode);
//寫某個數據段落
DWORD Write(const char* dname, const void *from, DWORD len);
//讀取某個數據段落
DWORD Read(const char* dname, void **to, DWORD &len);
//關閉文件流
void Close();
friend void testFileStream();
};
void testFileStream();
void testFileStream1();
}
#endif
//FileStream.cpp
#include "FileStream.h"
#ifndef DEL
#define DEL(p) { if(p) { delete (p); (p) = NULL; } }
#endif
#ifndef DELS
#define DELS(p) { if(p) { delete[] (p); (p) = NULL; } }
#endif
#ifndef RELEASE
#define RELEASE(p) { if(p) { (p)->Release(); (p) = NULL; } }
#endif
using namespace LK3D;
FileDataStreamBuffer::FileDataStreamBuffer(const char *dname)
{
zipbuflen = 0;
zipbuf = 0;
srcbuflen = 0;
dataname = dname;
}
DWORD FileDataStreamBuffer::GetSrcBufLen()
{
return srcbuflen;
}
FileDataStreamBuffer::~FileDataStreamBuffer()
{
DELS(zipbuf);
}
void FileDataStreamBuffer::realloc()
{
DELS(zipbuf);
zipbuf = new char[zipbuflen];
}
bool FileDataStreamBuffer::operator ==(const FileDataStreamBuffer &other) const
{
return GetLen() == other.GetLen() &&
dataname == other.dataname &&
zipbuflen == other.zipbuflen &&
memcmp((const char *)zipbuf, (const char *)other.zipbuf, zipbuflen) == 0 &&
srcbuflen == other.srcbuflen;
}
DWORD FileDataStreamBuffer::GetLen() const
{
// 文件名長度占位 文件名長度 srcbuf長度占位 zipbuf長度占位 zipbuf長度
return sizeof(DWORD) + (DWORD)dataname.size() + sizeof(DWORD) + sizeof(DWORD) + zipbuflen;
}
//寫字節
DWORD FileDataStreamBuffer::WriteBytes(const void *from,DWORD len)
{
if(dataname.empty())
return 0; //還未給要寫入的部分命名
if(!from)
return 0;
//記錄原字節數據區的長度
srcbuflen = len;
//重新分配zipbuf的空間
//DELS(zipbuf);
zipbuflen =(DWORD)(len+ (len * 0.1) + 12); //這是個公式,官方網站上提供的,預留的最小的壓縮空間的大小
realloc();
//壓縮原數據到zipbuf中去
compress2((Bytef*)zipbuf,(uLongf*)&zipbuflen,(const Bytef*)from,(uLongf)srcbuflen, Z_DEFAULT_COMPRESSION);
return len;
}
//讀字節
DWORD FileDataStreamBuffer::ReadBytes(void *to)
{
//if(dataname.empty())
// return 0; //還未給要讀取的部分命名
if(!to)
return 0;
uncompress((Bytef*)to, (uLongf *)&srcbuflen, (const Bytef*)zipbuf, (uLong)zipbuflen);
return zipbuflen;
}
void FileDataStreamBuffer::DumpBuffer()
{
DWORD len = zipbuflen;
printf("Buffer: size=%d", len);
if (len > 0)
{
printf(" [ ");
const UCHAR* pBuf = (const UCHAR*) zipbuf;
for (DWORD i = 0; i < len; ++i)
printf("%02X ", pBuf[i]);
printf("]");
}
printf("\n");
}
FileStream::FileStream(void)
{
pFile = 0;
}
FileStream::~FileStream(void)
{
Close();
}
//打開一個文檔
DWORD FileStream::Open(const char* archive,const char *mode)
{
pFile = fopen(archive, mode);
assert(pFile);
return 0;
}
//寫文件包
DWORD FileStream::Write(FileDataStreamBuffer& filebuf)
{
if(filebuf.dataname.empty())
{
return 0; //指定要讀取的數據區的名稱
}
DWORD writebytes = 0;
//寫入文件名的長度占位
DWORD filenamelen = (DWORD)filebuf.dataname.size();
writebytes+=(DWORD)(fwrite(&filenamelen, sizeof(DWORD), 1, pFile) * sizeof(DWORD));
//寫入文件名
writebytes+=(DWORD)(fwrite(filebuf.dataname.c_str(), sizeof(char), filebuf.dataname.size(), pFile) * sizeof(char));
//寫入srcbuf長度的占位
writebytes+=(DWORD)(fwrite(&filebuf.srcbuflen, sizeof(DWORD), 1, pFile) * sizeof(DWORD));
//寫入zipbuf的長度占位
writebytes+=(DWORD)(fwrite(&filebuf.zipbuflen, sizeof(DWORD), 1, pFile) * sizeof(DWORD));
//寫入zipbuf
writebytes+=(DWORD)(fwrite(filebuf.zipbuf, sizeof(char), filebuf.zipbuflen, pFile) * sizeof(char));
return writebytes;
}
//讀文件包
DWORD FileStream::Read(FileDataStreamBuffer& filebuf)
{
if(filebuf.dataname.empty())
{
return 0; //指定要讀取的數據區的名稱
}
//從文件頭開始
rewind(pFile);
char filename[100]; //文件名預留100應該足夠了
ZeroMemory(filename, 100);
//實際讀取的數量
DWORD readbytes = 0;
bool founded = false;
// bool bt = false;
// fseek(filebuf,1000, SEEK_CUR);
while(filebuf.dataname != filename)
{
//讀入文件名長度的占位
DWORD filenamelen = 0;
readbytes += (DWORD)(fread(&filenamelen, sizeof(DWORD), 1, pFile) * sizeof(DWORD));
if(readbytes == 0)
break; //已經無法讀取數據了,說明已經eof了
//讀入文件名
readbytes += (DWORD)(fread(&filename, sizeof(char), filenamelen, pFile) * sizeof(char));
//讀入srcbuf長度占位
readbytes += (DWORD)(fread(&filebuf.srcbuflen, sizeof(DWORD), 1, pFile) * sizeof(DWORD));
//讀入zipbuf長度占位
readbytes += (DWORD)(fread(&filebuf.zipbuflen, sizeof(DWORD), 1, pFile) * sizeof(DWORD));
if(filebuf.dataname == filename)
{
//重新分配可以裝載數據的空間
filebuf.realloc();
readbytes += (DWORD)(fread(filebuf.zipbuf, sizeof(char), filebuf.zipbuflen, pFile) * sizeof(char));
founded = true;
break;
}
else
{
readbytes = 0; //重新計數
//不是要找的data直接后移filebuf.zipbuflen
fseek(pFile, filebuf.zipbuflen, SEEK_CUR);
filebuf.zipbuflen = 0; //讀取的zipbuffer長度也清0,作廢處理
filebuf.srcbuflen = 0; //讀取的srcbuffer長度也清0,作廢處理
}
ZeroMemory(filename, 100);
}
if(founded)
return readbytes; //返回實際讀取的字節數
else
return 0; //讀取失敗了
}
//關閉文件流
void FileStream::Close()
{
if(pFile)
{
fclose(pFile);
pFile = 0;
}
}
DWORD FileStream::Write(const char* dname, const void *from,DWORD len)
{
FileDataStreamBuffer streambuf(dname);
if(!streambuf.WriteBytes(from, len))
return 0;
return Write(streambuf);
}
DWORD FileStream::Read(const char* dname, void **to, DWORD &len)
{
FileDataStreamBuffer streambuf(dname);
if(Read(streambuf))
{
if(*to)
{
printf("warning, 銷毀接收緩沖...");
DELS(*to)
}
len = streambuf.GetSrcBufLen();
*to = new char[len];
streambuf.ReadBytes(*to);
return len;
}
else
return 0;
}
void LK3D::testFileStream()
{
FileDataStreamBuffer f1("file1.txt");
char *str1 ="one 111";
f1.WriteBytes(str1, (DWORD)strlen(str1));
FileDataStreamBuffer f2("file2.txt");
char *str2 ="a111111111111111111b";
f2.WriteBytes(str2, (DWORD)strlen(str2));
FileStream stream;
//寫
stream.Open("aaa.bin", "wb");
DWORD d1 = stream.Write(f1);
DWORD d2 = stream.Write(f2);
assert(d1 == f1.GetLen());
assert(d2 == f2.GetLen());
stream.Close();
f2.DumpBuffer();
//讀
FileStream stream1;
stream1.Open("aaa.bin", "rb");
FileDataStreamBuffer val_bf("file2.txt");
DWORD vd2 = stream1.Read(val_bf);
stream1.Close();
val_bf.DumpBuffer();
if(vd2)
{
assert(vd2 == d2);
assert(f2 == val_bf);
char *c = new char[val_bf.GetSrcBufLen() +1];
ZeroMemory(c, val_bf.GetSrcBufLen() +1);
val_bf.ReadBytes(c);
printf("%s \r\n", c);
} else
{
printf("沒找到數據\r\n");
}
}
void LK3D::testFileStream1()
{
FileStream filestream;
filestream.Open("aaa.bin", "r+");
char *p=0;
DWORD ln = 0;
char *src = "hello,a big boy";
filestream.Write("xxx.xxx", src, (DWORD)strlen(src));
filestream.Read("xxx.xxx", (void **)&p, ln);
printf("%s :%d\r\n", p, ln);
DELS(p);
filestream.Close();
}