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

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

//获得文件在系统的绝对路径
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文件的部分源码:

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()函数时,出现了很多问题,如下面代码:

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}/下的代码(不过复制之前你应该先判断一下文件是否存在):

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;
}

你可能感兴趣的:(cocos2d-x-使用fopen函数读取assets里的内容导致crash)