cocos2dx android fopen读取文件失败

特别感谢:   Deepsky        帮忙解答

                       ♫⊹香草奶昔⌒    提供话题


        在cocos2dx中,提供了CCFileUitl来进行文件操作,但是大家一般习惯的方式还是仅仅通过这个类获取路径,然后用fopen相关的函数来操作,大概如下:

  string fullPath = fullPathForFilename(pszFileName);
  FILE *fp = fopen(fullPath.c_str(), pszMode);

        但是这样,windows和iOS正常无误,但是在android下面,会读取不到文件。之前遇到这个问题,没有解决,后面为了统一,改成了CCFileUtil的getFileData就没有出现过,也没有继续去追。

        今天追了之后,发现,在android下,CCFileUtil有独立实现,在cocos2d-x-2.2.3/cocos2dx/platform/android/下面(引擎版本2.2.3),CCFileUtilsAndroid。其中getFileData的实现如下:

unsigned char* CCFileUtilsAndroid::getFileData(const char* pszFileName, const char* pszMode, unsigned long * pSize)
{    
    return doGetFileData(pszFileName, pszMode, pSize, false);
}
unsigned char* CCFileUtilsAndroid::getFileDataForAsync(const char* pszFileName, const char* pszMode, unsigned long * pSize)
{
    return doGetFileData(pszFileName, pszMode, pSize, true);
}

unsigned char* CCFileUtilsAndroid::doGetFileData(const char* pszFileName, const char* pszMode, unsigned long * pSize, bool forAsync)
{
    unsigned char * pData = 0;
    
    if ((! pszFileName) || (! pszMode) || 0 == strlen(pszFileName))
    {
        return 0;
    }
    
    string fullPath = fullPathForFilename(pszFileName);
    
    if (fullPath[0] != '/')
    {
        if (forAsync)
        {   /********** !!!注意啊  ***********/
            pData = s_pZipFile->getFileData(fullPath.c_str(), pSize, s_pZipFile->_dataThread);
        }
        else
        {
            pData = s_pZipFile->getFileData(fullPath.c_str(), pSize);
        }
    }
    else
    {
        do
        {
            FILE *fp = fopen(fullPath.c_str(), pszMode);
            CC_BREAK_IF(!fp);
            
            unsigned long size;
            fseek(fp,0,SEEK_END);
            size = ftell(fp);
            fseek(fp,0,SEEK_SET);
            pData = new unsigned char[size];
            size = fread(pData,sizeof(unsigned char), size,fp);
            fclose(fp);
            
            if (pSize)
            {
                *pSize = size;
            }
        } while (0);
    }
    
    if (! pData)
    {
        std::string msg = "Get data from file(";
        msg.append(pszFileName).append(") failed!");
        CCLOG("%s", msg.c_str());
    }
    
    return pData;
}
        注意上面代码里面我标记注释的地方, 有个东西叫s_pZipFile,之前看到这里,没注意这个东西。仔细一看,前面的fullpath的返回值,是一个相对于asset/的文件,也就是说,基本上都会走这个if,那么这个s_pZipFile又是怎么定义的。        

#include "support/zip_support/ZipUtils.h"

// record the zip on the resource path
static ZipFile *s_pZipFile = NULL;

CCFileUtils* CCFileUtils::sharedFileUtils()
{
    if (s_sharedFileUtils == NULL)
    {
        s_sharedFileUtils = new CCFileUtilsAndroid();
        s_sharedFileUtils->init();
        std::string resourcePath = getApkPath();
        s_pZipFile = new ZipFile(resourcePath, "assets/");
    }
    return s_sharedFileUtils;
}
        重要的头文件我都留在上面了,所以其实上面那个getFileData的实现是这样的

unsigned char *ZipFile::getFileData(const std::string &fileName, unsigned long *pSize, ZipFilePrivate *data)
{
    unsigned char * pBuffer = NULL;
    if (pSize)
    {
        *pSize = 0;
    }
    
    do
    {
        CC_BREAK_IF(!data->zipFile);
        CC_BREAK_IF(fileName.empty());
        
        ZipFilePrivate::FileListContainer::const_iterator it = data->fileList.find(fileName);
        CC_BREAK_IF(it ==  data->fileList.end());
        
        ZipEntryInfo fileInfo = it->second;
        
        int nRet = unzGoToFilePos(data->zipFile, &fileInfo.pos);
        CC_BREAK_IF(UNZ_OK != nRet);
        
        nRet = unzOpenCurrentFile(data->zipFile);
        CC_BREAK_IF(UNZ_OK != nRet);
        
        pBuffer = new unsigned char[fileInfo.uncompressed_size];
        int CC_UNUSED nSize = unzReadCurrentFile(data->zipFile, pBuffer, fileInfo.uncompressed_size);
        CCAssert(nSize == 0 || nSize == (int)fileInfo.uncompressed_size, "the file size is wrong");
        
        if (pSize)
        {
            *pSize = fileInfo.uncompressed_size;
        }
        unzCloseCurrentFile(data->zipFile);
    } while (0);
    
    return pBuffer;
}
        基本上到这,问题就清楚了, 总结起来就是2点

        一、assets其实是一个zip压缩文件,直接读取里面的内容是不行的。

        二、android的实现和其他2个平台不一样。


        解决办法:

        最简单的,直接用CCFileUtil的getFileData实现文件读取。

        不然就从上面提到的文件去改。。。




其他方法,参考:1、 http://www.cppblog.com/johndragon/archive/2012/12/28/196754.html 

     2、 http://blog.csdn.net/happyhell/article/details/7414110

你可能感兴趣的:(cocos2d-x,android笔记,移动应用)