Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
202 views
in Technique[技术] by (71.8m points)

Importing Sqlite Database from a File in Flutter

I have a Sqlite database file that is always in the same spot on the device, in Documents named backup.db. What I want is to import that database to replace existing Sqlite database, but I am getting some strange errors. Anyways, here is the code:

  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);
  }
}

As far as I got, it gets the 'documents' directory, merges the path with backup.db file that already exists in Documents, then it should just import it if it exists. Let me know if there is anything I am doing wrong. I am using the ext_storage library to locate the documents folder and sqlite of course to be able to import the database.

And in another screen I call this function like this:

DbHelper dbHelper = new DbHelper();

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

Here's the stacktrace:

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)

When I tap on the button to import the database, it is completely unresponsive, not sure what the issue is.

question from:https://stackoverflow.com/questions/65871806/importing-sqlite-database-from-a-file-in-flutter

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Try the code below. It is similar to what you want but also with a versioning system. When you init the database, it will open the database in the phone directory and check the version of that. If it's outdated or doesn't exist it will delete the current one and create a new one (or just create a new one in the case that it doesn't exist).

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);
  }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...