zoukankan      html  css  js  c++  java
  • cocos2d-x-使用fopen函数读取assets里的内容导致crash

    

    cocos2d-x-使用fopen函数读取assets里的内容导致crash

    2012年11月25日 发表评论 阅读评论 7,613 人阅读    

    最近把win32和ios上运行成功的游戏移植到android时,程序直接挂了,查到原因是:使用fopen读取assets里的数据会导致应用crash,因为数据已经被压缩打包进apk文件里了。
    解决办法:
    1.使用cocos2d-x提供的CCFileUtils工具类
    2.把assets中的文件读取出来复制到/data/data/you_app_packagename/或者sd卡目录下,然后再使用fopen函数读取。
    下面来看看如何使用CCFileUtils工具类读取assets目录下的文件,代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    //获得文件在系统的绝对路径
    const char *filepath = CCFileUtils::fullPathFromRelativePath(filename);
    //读取的字节数,读取失败则为0
    unsigned long len = 0;
    //读取的内容
    unsigned char *data = CCFileUtils::getFileData(filepath, "r", &len);;
    //记得释放内存
    if(len >0 && data) delete[] data;

    cocos2d-x会根据具体的平台调用CCFileUtils对应的实现类,win32是CCFileUtils_win32.cpp,android平台是CCFileUtils_andorid.cpp,
    下面是CCFileUtils_andorid.cpp文件的部分源码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    unsigned char* CCFileUtils::getFileData(const char* pszFileName, const char* pszMode, unsigned long * pSize)
    {   
        unsigned char * pData = 0;
        string fullPath(pszFileName);
      
        if ((! pszFileName) || (! pszMode))
        {
            return 0;
        }
      
        if (pszFileName[0] != '/')
        {
            // read from apk
            fullPath.insert(0, "assets/");
            pData =  CCFileUtils::getFileDataFromZip(s_strResourcePath.c_str(), fullPath.c_str(), pSize);
        }
        else
        {
            do 
            {
                // read rrom other path than user set it
                FILE *fp = fopen(pszFileName, 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 && getIsPopupNotify())
        {
            std::string title = "Notification";
            std::string msg = "Get data from file(";
            msg.append(fullPath.c_str()).append(") failed!");
            CCMessageBox(msg.c_str(), title.c_str());
        }
      
        return pData;
    }

    当读取的文件名称是类似于”/test.txt”时,是使用fopen()函数的,这不是读取apk文件里的文件,是没有问题的,比如读取/data/data/packagename/xxx.txt。
    最近我在android平台使用fopen()函数时,出现了很多问题,如下面代码:

    1
    2
    3
    4
    5
    6
    7
    FILE* m_pFile = fopen(filepath,"r");
    char ch = getc(m_pFile);
    while(ch != EOF)
    {
    ... 
    ch=getc(m_pFile);
    }

    在android平台这个while循环会无限循环,导致模拟器黑屏了。原来读到文件末尾时,ch的值为255,不等于EOF,改成while(ch != EOF && ch!= 255)就行了。
    当文件名称是”test.txt”时,此时调用的是getFileDataFromZip()这个函数,读取apk压缩包assets里的文件。

    下面附上把apk中assets目录下的文件拷贝到/data/data/${packagename}/下的代码(不过复制之前你应该先判断一下文件是否存在):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    bool isFileExist(const char* pFileName)
    {
        if( !pFileName ) return false;
        //strFilePathName is :/data/data/ + package name
        std::string filePath = CCFileUtils::getWriteablePath();
        filePathName += pFileName;
      
        FILE *fp = fopen(filePath.c_str(),"r");
        if(fp)
        {
            fclose(fp);
            return true;
        }
        return false;
    }
      
    void copyData(const char* pFileName)
    {
        std::string strPath = CCFileUtils::fullPathFromRelativePath(pFileName);
        unsigned long len = 0;
        unsigned char *data = NULL;
      
        data = CCFileUtils::getFileData(strPath.c_str(),"r",&len);
        std::string destPath = CCFileUtils::getWriteablePath();
        destPath += pFileName;
        FILE *fp = fopen(destPath.c_str(),"w+");
        fwrite(data,sizeof(char),len,fp);
        fclose(fp);
        delete []data;
        data = NULL;
    }
  • 相关阅读:
    ReactJS读书笔记一:深入理解JSX
    react经验
    React显示和提交数据
    ReactJS
    PHP中使用memcache
    项目目标文档 ---河北省创新平台年报统计
    系统利益相关者描述案例
    梦断代码 --阅读笔记03
    梦断代码 ---阅读笔记02
    梦断代码---读书笔记01
  • 原文地址:https://www.cnblogs.com/xiayong123/p/3716971.html
Copyright © 2011-2022 走看看