本人写的cocos2d-x资源文件打包成一个文件的源代码,原理比较简单,就是把所有要打包的文件顺序保存在一个文件里,然后在文件末尾维护一份文件列表,文件头保存文件列表的偏移地址,具体代码在github
https://github.com/alexviolent/AssetsPack.git
AssetsFile.h
#ifndef __ASSETSFILE_H__
#define __ASSETSFILE_H__
class AssetsPack;
class AssetsFile
{
public:
AssetsFile(AssetsPack* package,unsigned int offset,unsigned int nameHash,unsigned int fileSize);
~AssetsFile();
int read(unsigned char* buff);
//int compress();
//int unCompress();
unsigned int getSize(){return _size;};
unsigned int getNameHash(){return _nameHash;};
private:
bool _isCompressed;
unsigned int _size;
unsigned int _offset;
unsigned int _nameHash;
AssetsPack* _package;
};
#endif
```
AssetsFile.cpp
#include "AssetsFile.h"
#include "Pack.h"
AssetsFile::AssetsFile( AssetsPack* package,uint offset,uint nameHash,uint fileSize )
{
_package=package;
_offset=offset;
_nameHash=nameHash;
_size=fileSize;
}
AssetsFile::~AssetsFile()
{
}
int AssetsFile::read( uchar* buff )
{
return _package->read(buff,_offset,_size);
}
```
Pack.h
#include
#include
#include "AssetsFile.h"
#ifndef __ASSETSPACK_H__
#define __ASSETSPACK_H__
typedef unsigned char uchar;
typedef unsigned int uint;
const uchar FILE_NORMAL = 1;
const uchar FILE_DELETE = 2;
const uchar FILE_COMPRESS = 3;
struct PackageHeader
{
uint fileEntryOffset;
int fileAmount;
};
struct FileEntry
{
uint offset;
uint nameHash;
uint fileSize;
uchar flag;
};
class AssetsPack
{
public:
AssetsPack(const char* fileName);
~AssetsPack();
AssetsFile* openFile(uint hash);
AssetsFile* openFile(const char* fileName);
bool hasFile(const char* fileName);
void delFile(uint hash);
void delFile(const char* fileName);
void addFile(uint hash,const uchar* buff,uint len);
void addFile(const char* fileName,const uchar* buff,uint len);
void flush();
void mergeWith(AssetsPack* package);
void extractTo(const char* dir);
int read(uchar* buff,uint offset,uint len);
bool isValid(){return _isValid;};
std::vector& getFileEntry(){return _vectorFileEntry;};
private:
void readFileEntry();
void writeFileEntry();
/*获取已经删除文件的入口,如果文件大小大于等于size,就可以覆盖*/
FileEntry* getDirtyEntry(uint size);
private:
int _size;
bool _isValid;
PackageHeader _packageHeader;
std::vector _vectorFileEntry;
FILE* _file;
std::string _fileName;
};
#endif
```
Pack.cpp
#include "Pack.h"
#include "AssetsFile.h"
uint BKDRHash(const char* str)
{
uint seed=131;
uint hash=0;
int len=strlen(str);
for (int i=0;i=8)
{
fread(&_packageHeader,1,sizeof(PackageHeader),_file);
readFileEntry();
}
else
{
fwrite(&_packageHeader,1,sizeof(PackageHeader),_file);
}
}
AssetsPack::~AssetsPack()
{
if (_file!=NULL)
{
fclose(_file);
}
}
void AssetsPack::readFileEntry()
{
if (!_isValid) return;
fseek(_file,_packageHeader.fileEntryOffset,SEEK_SET);
for (int i=0;i<_packageHeader.fileAmount;i++)
{
FileEntry entry;
fread(&entry,1,sizeof(FileEntry),_file);
_vectorFileEntry.push_back(entry);
}
}
void AssetsPack::writeFileEntry()
{
fseek(_file,_packageHeader.fileEntryOffset,SEEK_SET);
for (int i=0;i<_vectorFileEntry.size();i++)
{
FileEntry entry=_vectorFileEntry*;
fwrite(&entry,1,sizeof(FileEntry),_file);
}
}
void AssetsPack::addFile( uint hash,const uchar* buff,uint len )
{
delFile(hash);
FileEntry entry;
entry.fileSize=len;
entry.nameHash=hash;
FileEntry* dirtyEntry=getDirtyEntry(len);
if (dirtyEntry!=NULL)
{
entry.offset=dirtyEntry->offset;
dirtyEntry->fileSize=len;
dirtyEntry->flag=FILE_NORMAL;
}
else
{
entry.flag=FILE_NORMAL;
entry.offset=_packageHeader.fileEntryOffset;
_vectorFileEntry.push_back(entry);
_packageHeader.fileAmount++;
_packageHeader.fileEntryOffset+=len;
}
fseek(_file,entry.offset,SEEK_SET);
fwrite(buff,1,len,_file);
}
void AssetsPack::addFile( const char* fileName,const uchar* buff,uint len )
{
uint hash=BKDRHash(fileName);
addFile(hash,buff,len);
}
AssetsFile* AssetsPack::openFile( uint hash )
{
for (uint i=0;i<_vectorFileEntry.size();i++)
{
FileEntry& entry=_vectorFileEntry*;
if (entry.flag!=FILE_DELETE&&entry.nameHash==hash)
{
AssetsFile* file=new AssetsFile(this,entry.offset,entry.nameHash,entry.fileSize);
return file;
}
}
return NULL;
}
AssetsFile* AssetsPack::openFile( const char* fileName )
{
uint hash=BKDRHash(fileName);
return openFile(hash);
}
void AssetsPack::flush()
{
writeFileEntry();
fseek(_file,0,SEEK_SET);
fwrite(&_packageHeader,1,sizeof(PackageHeader),_file);
fclose(_file);
_file=fopen(_fileName.c_str(),"rb+");
}
int AssetsPack::read( uchar* buff,uint offset,uint len )
{
fseek(_file,offset,SEEK_SET);
uint r=fread(buff,1,len,_file);
return r;
}
bool AssetsPack::hasFile( const char* fileName )
{
uint hash=BKDRHash(fileName);
for (uint i=0;i<_vectorFileEntry.size();i++)
{
FileEntry& entry=_vectorFileEntry*;
if (entry.flag!=FILE_DELETE&&entry.nameHash==hash)
{
return true;
}
}
return false;
}
void AssetsPack::delFile( uint hash )
{
for (uint i=0;i<_vectorFileEntry.size();i++)
{
FileEntry& entry=_vectorFileEntry*;
if (entry.flag!=FILE_DELETE&&entry.nameHash==hash)
{
entry.flag=FILE_DELETE;
return;
}
}
}
void AssetsPack::delFile( const char* fileName )
{
uint hash=BKDRHash(fileName);
delFile(hash);
}
void AssetsPack::mergeWith( AssetsPack* package )
{
std::vector vectorFileEntry=package->getFileEntry();
if (vectorFileEntry.size()<=0) return;
uchar* buff=(uchar*)malloc(1024*1024*10);
for (uint i=0;iopenFile(entry.nameHash);
if (file!=NULL)
{
uint size=file->getSize();
file->read(buff);
addFile(file->getNameHash(),buff,size);
}
}
free(buff);
flush();
}
void AssetsPack::extractTo( const char* dir )
{
for (uint i=0;i<_vectorFileEntry.size();i++)
{
FileEntry& entry=_vectorFileEntry*;
if (entry.flag!=FILE_DELETE)
{
}
}
}
FileEntry* AssetsPack::getDirtyEntry( uint size )
{
for (uint i=0;i<_vectorFileEntry.size();i++)
{
FileEntry* entry=&_vectorFileEntry*;
if (entry->flag==FILE_DELETE)
{
if (entry->fileSize>=size)
{
return entry;
}
}
}
return NULL;
}
```
PS:本代码只是压缩和读取代码,如果要配合2dx来使用,需要修改CCFileUtils相关的代码才行哦。由于调用的是标准的C文件操作,所以ANDROID在读写打包后的文件之前,在第一次游戏初始化的时候要先把文件拷贝到writeablepath,ios就可以直接操作。
欢迎加群讨论研究cocos2dx 群名称是cocos2dx手游精英群 166029496 ********