You need to enable JavaScript to run this app. Android平台下使用std::ifstream获取文件大小返回0的解决方法
优惠活动
大模型
产品
解决方案
定价
更多

Android平台下使用std::ifstream获取文件大小返回0的解决方法

Android 平台基于 std::ifstream 获取文件大小的可靠实现

现有代码的失效原因

原实现拿到0值并非随机问题,是三类常见的平台适配坑叠加导致的,其中也包含明确的格式层面问题:

  • 低版本STL对ios::ate标记的实现缺陷
    旧版NDK内置的STL中,打开文件时附带std::ios::ate标记并不会稳定把文件指针定位到末尾,多数场景下指针仍停留在文件起始位置,此时调用tellg自然返回0。
  • 变参传递的类型不匹配(格式层面问题)
    tellg() 返回值是 std::streampos 类类型,并非原生整数。代码中使用%ld占位符期待接收一个long类型的整数,实际传入的是类类型的非POD值,二者ABI规则不兼容。直接将该类型作为可变参数传入 __android_log_print 这类C风格变参函数时,ARM架构下会将传参值处理成0,完全丢失真实的位置信息。
  • 流状态校验缺失
    仅通过is_open()判断文件可访问并不充分:当流因为权限不足、文件被截断、磁盘IO错误进入fail/bad状态时,tellg会返回无效位置,现有代码不会触发错误分支就直接使用返回值。

全版本兼容的可靠实现

这套方案不需要依赖std::filesystem,从API 16到最新Android版本均可稳定运行:

std::ifstream f(filePath, std::ios::binary);
if (!f.is_open()) {
    ALOGV(TAG, "problem opening file");
    return;
}
// 主动定位到文件末尾,兼容低版本STL的ate标记实现缺陷
f.seekg(0, std::ios::end);
if (f.fail()) {
    ALOGV(TAG, "seek to file end failed");
    f.close();
    return;
}
std::streampos endPos = f.tellg();
// 校验位置获取是否有效
if (endPos == std::streampos(-1)) {
    ALOGV(TAG, "tellg failed to read file position");
    f.close();
    return;
}
// 显式转为原生整数类型,适配32/64位架构
auto fileSize = static_cast<long long>(endPos);
f.close();
__android_log_print(ANDROID_LOG_VERBOSE, "my tag", "filesize: %lld", fileSize);

编译与使用注意事项

  • 工程编译时统一选择c++_static或c++_shared作为STL实现,废弃已停止维护的gnustl_shared,该STL的文件流定位逻辑存在已知bug
  • 访问应用外部存储路径时,需确认已申请对应存储权限,否则哪怕文件真实存在,流也会进入不可用的fail状态
  • 测量文件大小的流程中不要穿插其他文件读写操作,避免流状态被污染

内容的提问来源于stack exchange,提问作者Gatonito

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.05 07:06:04