最近把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;
}
|
转载请注明来自:Alex Zhou的程序世界,本文链接:http://codingnow.cn/cocos2d-x/939.html