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
相关产品推荐
相关产品推荐

