You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter加载2GB SQLite资产数据库报错,求解决方案

解决Flutter加载2GB SQLite数据库的内存限制问题

问题根源

你遇到的NewExternalTypedData expects argument 'length' to be in the range [0..1073741823]错误,本质是Dart的TypedData(包括Uint8List)单个对象的最大长度被限制在1GB(即2^30 -1)。你的2GB数据库用rootBundle.load一次性加载到内存,直接触发了这个限制。

解决方案:分块读取assets文件

不要一次性加载整个数据库到内存,改用分块读取assets字节流 + 分块写入目标文件的方式,避免内存溢出。

1. 修改pubspec.yaml,禁止压缩数据库文件

Flutter默认会压缩assets中的文件,大数据库被压缩后不仅读取效率低,还可能导致复制后无法正常打开。在pubspec.yaml中添加dontCompress配置:

dependencies:
  path: ^1.9.0
  path_provider: ^2.1.3
  sqflite: ^2.3.3+1

flutter:
  assets:
    - path: assets/database/library.db
      dontCompress: true  # 禁止压缩该大文件

2. 替换数据库复制逻辑

把原来一次性加载写入的代码,替换为分块读写的实现:

Future<Database?> get database async {
  if (_db != null) return _db;

  Directory applicationDirectory = await getApplicationDocumentsDirectory();
  String dbPath = join(applicationDirectory.path, "library.db");
  bool isDBExists = await File(dbPath).exists();

  if (!isDBExists) {
    // 打开assets的字节流(而非一次性加载)
    final ByteStream assetStream = rootBundle.open(join("assets", "database/library.db"));
    final File targetFile = File(dbPath);
    final IOSink fileSink = targetFile.openWrite();

    // 分块读取并写入,每块设为64MB(可根据设备内存调整)
    await assetStream.listen(
      (List<int> chunk) {
        fileSink.add(chunk);
      },
      onDone: () async {
        await fileSink.close();
      },
      onError: (error) {
        fileSink.close();
        throw Exception("复制数据库失败: $error");
      },
    ).asFuture();
  }

  _db = await openDatabase(dbPath);
  return _db;
}

额外建议

  • 分块大小可以调整,比如32MB、64MB都可以,不要超过1GB即可。
  • 2GB的数据库打包进APK会导致安装包体积过大,建议考虑通过网络下载数据库到设备存储,或者使用Android的OBB扩展文件存储大资源,优化应用分发体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 00:33:27