首页 > 解决方案 > 在 Flutter 中从文件中导入 Sqlite 数据库

问题描述

我有一个 Sqlite 数据库文件,它始终位于设备上的同一位置,位于名为 backup.db 的文档中。我想要的是导入该数据库以替换现有的 Sqlite 数据库,但我遇到了一些奇怪的错误。无论如何,这里是代码:

  class DbHelper {
  static const currentDatabaseVersion = 1;

  Future<void> init() async {
    Database db;

    final dbPath = await ExtStorage.getExternalStoragePublicDirectory(
        ExtStorage.DIRECTORY_DOCUMENTS);
    final newPath = join(dbPath, '/backup.db');

    String localDatabasePath = newPath;

    //Internal database path
    var databasesPath = await getDatabasesPath();
    var path = join(databasesPath, "foodDB.db");
    db = await openDatabase(path);

    if (await db.getVersion() < currentDatabaseVersion) {
      db.close();
      await deleteDatabase(path);

      await _checkParentDirectoryExists(path);

      ByteData data = await _getByteDataFromLocalDatabase(localDatabasePath);
      List<int> bytes = _databaseByteDataToList(data);
      await _writeBytesToInternalDatabase(path, bytes);

      db = await openDatabase(path);
      db.setVersion(currentDatabaseVersion);
    }
  }

  static Future<void> _checkParentDirectoryExists(var path) async {
    try {
      await Directory(dirname(path)).create(recursive: true);
    } catch (e) {
      print(e);
    }
  }

  static Future<ByteData> _getByteDataFromLocalDatabase(
      String localDatabasePath) async {
    return await rootBundle.load(join(localDatabasePath));
  }

  static List<int> _databaseByteDataToList(ByteData data) {
    return data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
  }

  static Future<void> _writeBytesToInternalDatabase(
      var path, List<int> bytes) async {
    await File(path).writeAsBytes(bytes, flush: true);
  }
}

据我所知,它获取'documents'目录,将路径与Documents中已经存在的backup.db文件合并,然后如果它存在,它应该只导入它。让我知道我做错了什么。我正在使用ext_storage库来定位文档文件夹和sqlite当然能够导入数据库。

在另一个屏幕中,我这样调用这个函数:

DbHelper dbHelper = new DbHelper();

onTap: () => dbHelper.init(),

这是堆栈跟踪:

ter (25910): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: Unable to load asset: /backup.db
E/flutter (25910): #0      PlatformAssetBundle.load
package:flutter/…/services/asset_bundle.dart:225
E/flutter (25910): <asynchronous suspension>
E/flutter (25910): #1      DbHelper._getByteDataFromLocalDatabase
package:CWCFlutter/db/import_database.dart:72
E/flutter (25910): #2      DbHelper.init
package:CWCFlutter/db/import_database.dart:53
E/flutter (25910): <asynchronous suspension>
E/flutter (25910): #3      _FoodListState.build.<anonymous closure>
package:CWCFlutter/food_list.dart:919
E/flutter (25910): #4      GestureRecognizer.invokeCallback
package:flutter/…/gestures/recognizer.dart:183
E/flutter (25910): #5      TapGestureRecognizer.handleTapUp
package:flutter/…/gestures/tap.dart:598
E/flutter (25910): #6      BaseTapGestureRecognizer._checkUp
package:flutter/…/gestures/tap.dart:287
E/flutter (25910): #7      BaseTapGestureRecognizer.acceptGesture
package:flutter/…/gestures/tap.dart:259
E/flutter (25910): #8      GestureArenaManager.sweep
package:flutter/…/gestures/arena.dart:157
E/flutter (25910): #9      GestureBinding.handleEvent
package:flutter/…/gestures/binding.dart:362
E/flutter (25910): #10     GestureBinding.dispatchEvent
package:flutter/…/gestures/binding.dart:338
E/flutter (25910): #11     RendererBinding.dispatchEvent
package:flutter/…/rendering/binding.dart:267
E/flutter (25910): #12     GestureBinding._handlePointerEvent
package:flutter/…/gestures/binding.dart:295
E/flutter (25910): #13     GestureBinding._flushPointerEventQueue
package:flutter/…/gestures/binding.dart:240
E/flutter (25910): #14     GestureBinding._handlePointerDataPacket
package:flutter/…/gestures/binding.dart:213
E/flutter (25910): #15     _rootRunUnary (dart:async/zone.dart:1206:13)
E/flutter (25910): #16     _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter (25910): #17     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1005:7)
E/flutter (25910): #18     _invoke1 (dart:ui/hooks.dart:265:10)
E/flutter (25910): #19     _dispatchPointerDataPacket (dart:ui/hooks.dart:174:5)

当我点击按钮导入数据库时​​,它完全没有响应,不确定是什么问题。

标签: sqliteflutterdart

解决方案


试试下面的代码。它与您想要的类似,但也具有版本控制系统。当您init创建数据库时,它将在手机目录中打开数据库并检查其版本。如果它已过时或不存在,它将删除当前的并创建一个新的(或者在它不存在的情况下创建一个新的)。

static const currentDatabaseVersion = 1;

static Future<void> init() async {
    Database db;

    String localDatabasePath = 'your database path here';

    //Internal database path
    var databasesPath = await getDatabasesPath();
    var path = join(databasesPath, "database.db");
    db = await openDatabase(path);

    if (await db.getVersion() < currentDatabaseVersion) {
      db.close();
      await deleteDatabase(path);

      await _checkParentDirectoryExists(path);

      ByteData data = await _getByteDataFromLocalDatabase(localDatabasePath);
      List<int> bytes = _databaseByteDataToList(data);
      await _writeBytesToInternalDatabase(path, bytes);

      db = await openDatabase(path);
      db.setVersion(currentDatabaseVersion);
    }
  }

  static Future<void> _checkParentDirectoryExists(var path) async {
    try {
      await Directory(dirname(path)).create(recursive: true);
    } catch (e) {
      print(e);
    }
  }

  static Future<ByteData> _getByteDataFromLocalDatabase(
      String localDatabasePath) async {
    return await rootBundle.load(join(localDatabasePath));
  }

  static List<int> _databaseByteDataToList(ByteData data) {
    return data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
  }

  static Future<void> _writeBytesToInternalDatabase(
      var path, List<int> bytes) async {
    await File(path).writeAsBytes(bytes, flush: true);
  }

推荐阅读