10M以上的文件用size作为判断条件好像就会对不上了,打印出来的asset.size值和project.manifest中存的值会不同,getFileSize获取到的是精确的值。
粗略的看了一下asset.size用的是float,超过七位大概是10M是不是就会精度丢失了啊,不过不太懂c++不知道是不是这个原因造成的。
这么多年用下来的方案,看了论坛里面没人反应过这个问题,最佳实践是都只用md5做判断吗,还是说不应该有10M以上的文件。
截止到今日(2025年10月27日),这个问题还在,我本打算使用size代替md5做文件效验,毕竟获取md5要慢很多。我的文件大小为17.3M,符合楼主提到的大于10M说法,我当前使用的最新的官方版本:3.8.7,官方一直都没有修复这个问题,通过setVerifyCallback回调中获取到的size比我打到project.manifest中的size多1,我理解的是,文件大小使用的是字节单位,不应该直接用整数类型就可以吗?另外一个疑惑点,回调中返回的size数值,应该直接从project.manifest中获取就可以了,为什么会出现数值不一致的情况呢?
通过查看C++源码,找到了问题的根源:int转float过程中,导致数据精度丢失。具体文件位置如下:
C:\ProgramData\cocos\editors\Creator\3.8.8\resources\resources\3d\engine\native\extensions\assets-manager\Manifest.cpp 中 Manifest::Asset Manifest::parseAsset(const std::string &path, const rapidjson::Value &json){} 函数中,关键代码如下:
突然发现这个平台编辑器也有bug,会自动去掉代码中的尖括号,太坑爹了,只能用图片展示代码:
![]()
asset.size = static_cast(json[KEY_SIZE].GetInt()); // 这行代码中的尖括号被平台编辑器自动去掉了
测试中原始size=32515387,转成float后的值为:32515388;
当size的原始大小超过16777217(大约16M)的时候就会出现精度丢失的情况,具体原因如下:
1、float 的尾数只有 23 位,超过的部分会被截取掉;
2、截取需要遵循舍入规则(就近舍入,偶舍入),并不是简单截取舍弃掉,这也说明了为什么精度丢失后数值反而变大了;
3、拿数字32515387(对应文件大小为:31.0 MB)来举例说明,它转成float对应的格式为:1.11110000001001010011110 × 2^24,如果不截取,格式为:1.111100000010010100111011 × 2^24,正因为舍弃过程中产生了进位(具体操作细节自行网络搜索),然后将截取后的float值转回int类型,得到:1.11110000001001010011110 × 2^24 = 32515388,从而比实际值多了1;
解决方案:
1、可以将float类型换成double类型;
2、可以将float类型换成uint32_t类型,可以支持单文件大小为:4GB,基本上也够用了;
具体修改文件位置如下:
位置1:extensions/assets-manager/Manifest.h
将DownloadUnit结构体和ManifestAsset结构体中的size类型从float改成double或者uint32_t类型;
位置2:extensions/assets-manager/Manifest.cpp
将函数:Manifest::Asset Manifest::parseAsset(const std::string &path, const rapidjson::Value &json)中:
