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

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