I'm creating an encrypted sqflite database with sqflite_sqlcipher and would like to open it with the DB Browser for SQLCipher. For that i only need to find my .db file but I can't seem to figure out where this file is stored inside my app.
I have printed the path to the db in my init function and the output is below:
Future<Database> _initDatabase() async {
print("Database path: ${await getDatabasesPath()}");
final dbPath = await getDatabasesPath();
final path = join(dbPath, "documents.db");
final pw = await getPassword();
return await openDatabase(
path,
password: pw,
version: 1,
onCreate: _onCreate,
);
}
Database path: /data/user/0/com.example.did/databases
You could access it using Android Studio, look for Device File Manager and from there, you can access the file path.
Related
the app works with sqlite database and it shows the data that exits in the assets very fine even though when the app closed those data is still there , the problem is when connecting with server and loading data it is saved and displayed in the app very fine but only when the app running , if the app closed every thing lost and I just found the data that already exists in assets from the beginning .
how I can save the data that loading from the server in local database even if the app is closed?
here is my database initialize function
Future<Database> initDb() async {
if (kIsWeb) {
try {
} catch (_) {}
// Set web-specific directory Here
} else {
Directory documentDirectory = await getApplicationDocumentsDirectory();
String path = join(documentDirectory.path, "data_4us.db");
// Load database from asset and copy
ByteData data = await rootBundle.load(join('data', '4us.db'));
List<int> bytes =
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
// Save copied asset to documents
await new File(path).writeAsBytes(bytes);
var ourDb = await openDatabase(path);
return ourDb;
} }
Ok guys, I think I solve the problem
I just add this if statement to check the existing of the database
if (FileSystemEntity.typeSync(path) == FileSystemEntityType.notFound){ }
now everything is fine.
thank you .
There's some very odd problems when using flutter for MacOs apps.
I'm using the following Database initialisation:
_initDatabase() async {
Directory dbDirectory = await getApplicationDocumentsDirectory();
String path = join(dbDirectory.path, _databaseName);
//ByteData data = await rootBundle.load("assets/mydatabase.sqlite");
//List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
//await File(path).writeAsBytes(bytes);
return await openDatabase(path,
version: _databaseVersion,
//onCreate: _onCreate
);}
What is the issue?
I keep on getting error that it cannot find the table. The table absolutely exists.
But then I checked the logs and it appears it is using the /Users/myname/Documents to store the database file.
that's not what I want. The database file for this application is in the assets folder, and it should remain (when it is packaged) within the app bundle.
How do I specify the assets folder??
What am I doing wrong??
The create function, by the way, isn't working either.
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE $table (
$columnId INTEGER PRIMARY KEY,
$col1 TEXT,
$col2 TEXT,
$col3 TEXT
)
''');}
Im exhausted from trying...
Minimal reproducible code:
class Helper {
Database _db;
Future<Database> initDb() async {
if (_db == null) {
final directory = await getApplicationDocumentsDirectory();
_db = await openDatabase(join(directory.path, 'foo.db'), version: 1, onCreate: _onCreate);
}
return _db;
}
Future<void> _onCreate(Database db, _) async {
print('onCreate');
await db.transaction((txn) async {
await txn.execute('CREATE TABLE tableName(abc TEXT)');
});
}
}
Here's my main method:
void main() async {
final directory = await getApplicationDocumentsDirectory();
final file = File(join(directory.path, 'foo.db'));
if (await file.exists()) {
await file.delete();
}
// If there had been a file, it's deleted now.
final helper = Helper();
await helper.initDb(); // This must fire `onCreate` but it doesn't.
}
Every time you run the main method, it should execute the onCreate method in Helper class but it only does that once. What am I doing wrong here?
The issue description has changed since the beginning and it is not easy to make a proper explanation in a comment so here is yet another answer.
All existing responses remain valid but the issue now is moving to something like onCreate not called after deleting the database.
Every time you run the main method, it should execute the onCreate method in Helper class but it only does that once. What am I doing wrong here?
You don't really specify how you run (i.e. do you stop the application before), so I'm assuming you are just pressing the run button on your IDE which performs a hot-restart.
While you might be enclined to simply delete the file, you should however use
deleteDatabase to properly delete a database.
// Do not call File.delete, it will not work in a hot restart scenario
await File(path).delete();
// Instead do
await deleteDatabase(path);
it will properly close any existing database connection
it will properly handle the hot-restart scenario which put SQLite in a
weird state (basically the 'dart' side think the database is closed while
the database is in fact open on the native side)
If you call File.delete, while you might think it work (i.e. the file does not
exist anymore), since the database might still be opened in a hot restart scenario
the next open will re-use the open connection and at some point will get written
with the old data and onCreate will not be called the next time you open
the database.
onCreate will be executed only when there is no database file. Not when there is no table in the db. If you delete database file then there will be a print in console with message onCreate. Here is an example:
void main() async {
final directory = await getApplicationDocumentsDirectory();
final path = join(directory.path, 'foo.db');
await File(path).delete();
final helper = Helper();
await helper.initDb();
// await helper.dropTable();
}
This code prints a log message every run of a program.
This is not how Sqflite works.
The very first time when you create a database you give it a version number. In your case the version is 1.
Sqflite will check if database exists on the devices if it exists it checks the version number of db on device and version number of your code, if version is not the same it will call onUpgrade if new version is greater than old db version. and on downgrade if old version is greater than new version. OnCreate won't be called. onCreate is only called the very first time user install your app. Even if you drop your tables afterwards. If you need to update your database in future on a production app, you have to write onUpgrade method, in which you have to explicitly drop your tables and call onCreate yourself. and upgrade the database version.
See the following code. Use this code setup and change version to a higher version number whenever you need to dropAll tables and createAgain.
If you don't want to use the versions and explicitly drop tables and recreate them. You have to call _onCreate yourself after dropping a table.
class Helper {
Database _db;
Future<Database> initDb() async {
if (_db == null) {
final directory = await getDatabasesPath();
final path = join(directory, 'foo.db');
_db = await openDatabase(
path,
version: 2, //+1 to this number whenever you want to update
onCreate: _onCreate,
onUpgrade: _onUpgrade,
);
}
return _db;
}
Future<void> _onUpgrade(
Database db, int previousVersion, int newVersion) async {
_db = db;
await dropTable();
await _onCreate(db, newVersion);
}
Future<void> _onCreate(Database db, int version) async {
print('onCreate');
await db.transaction((txn) async {
await txn.execute('CREATE TABLE tableName(abc TEXT)');
});
}
Future<void> dropTable() async {
await _db.transaction((txn) async {
await txn.execute('DROP TABLE IF EXISTS tableName');
});
}
It is the default behavior because onCreate Method is executed when you create the database. Since the database is created before it is not executed again.
If you intent to clean the rows of the table then use the TRUNCATE command. For more information check the link comparing drop table and truncate table here
Database database = await openDatabase(
dbPathWithDatabase,
version: 1,
onCreate: (Database database, int version) async {
print("\n\nCalling database on create\n\n");
ByteData data = await rootBundle.load(join("assets", "database.db"));
List<int> bytes =
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
print(bytes);
await new File(dbPathWithDatabase).writeAsBytes(bytes);
},
);
The above code is not copying the data to my database. But the database is created successfully.
database.db already exist in assets folder and i want to copy all the data from it.
Here i am calling it from openDatabase which cause the problem.
I can move the code above openDatabase. But i want to know the correct way to populate the data
As I am new to flutter, I have created new DB whenever I have faced an issue, But now I need to remove other unused DB's. How can I check existing DB and delete them except currently using?
//final demoDb = 'demoDb1.db';
//final demoDb = 'demoDb2.db';
//final demoDb = 'demoDb3.db';
//final demoDb = 'demoDb4.db';
final demoDb = 'demoDb5.db'; //Currently using this one
createDatabase() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, demoDb);
var database = await openDatabase(path,
version: 1, onCreate: initDB, onUpgrade: onUpgrade);
return database;
}
Thanks in advance.
There is no flutter to way to list existing databases, you can however list files (a sqflite database is a file) in the directory you created them (I suggest using getDatabasesPath instead of getApplicationDocumentsDirectory).
You can then check if database exists (databaseExists) and delete it (deleteDatabase) assuming it is not open (in this case you must close it first)