本人写的cocos2d-x资源文件打包成一个文件的源代码

本人写的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 ********

感谢你的分享。

赞一个

这个既能起到加密资源文件,又可以减少包的体积。