Я не верю, что доступ к базовому API-интерфейсу является тривиальной задачей, поэтому ответ, вероятно, да, НО.
Альтернативой, которая, к сожалению, недоступна в стандартном SQLite на Android, является использование VACUUM INTO (требуется SQLite 3.27.0 (если я правильно помню)) .
Однако сделать резервную копию из памяти в файл с помощью запросов не так уж сложно, и, вероятно, намного проще, чемвы ожидаете.
Следующий код является очень простым, скопируйте все таблицы (кроме таблиц с префиксом sqlite_ и android_metadata).
public class MainActivity extends AppCompatActivity {
SQLiteDatabase memorydb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
memorydb = SQLiteDatabase.create(null);
memorydb.execSQL("CREATE TABLE tablex (_id INTEGER PRIMARY KEY, name TEXT)");
memorydb.execSQL("INSERT INTO tablex (name) VALUES ('FRED'),('MARY'),('JANE')");
copyMemoryDBToFileDB();
memorydb.close();
}
private void copyMemoryDBToFileDB() {
String attachSchema = "diskdb";
File db = new File(getDatabasePath("mydb").getPath());
if (db.exists()) {
db.delete();
}
if (!db.getParentFile().exists()) {
db.getParentFile().mkdirs();
}
String dbFilePath = db.getPath();
SQLiteDatabase dbFile = SQLiteDatabase.openDatabase(dbFilePath, null, SQLiteDatabase.CREATE_IF_NECESSARY);
dbFile.setForeignKeyConstraintsEnabled(false);
dbFile.close();
memorydb.beginTransaction();
memorydb.execSQL("ATTACH DATABASE '" + dbFilePath + "' AS " + attachSchema);
//Cursor csr = memorydb.rawQuery("SELECT * FROM sqlite_master WHERE type=?",new String[]{"table"});
Cursor csr = memorydb.query("main.sqlite_master", null, "type=?", new String[]{"table"}, null, null, null);
while (csr.moveToNext()) {
String currentTable = csr.getString(csr.getColumnIndex("name"));
String dbfileTable = attachSchema + "." + currentTable;
if (currentTable.startsWith("sqlite_") || currentTable.equals("android_metadata"))
continue;
String crtSQL = csr.getString(csr.getColumnIndex("sql"))
.replace(currentTable, dbfileTable).replace("CREATE TABLE ", "CREATE TABLE IF NOT EXISTS ");
memorydb.execSQL(crtSQL);
memorydb.execSQL("INSERT INTO " + dbfileTable + " SELECT * FROM " + currentTable);
}
memorydb.setTransactionSuccessful();
memorydb.endTransaction();
memorydb.execSQL("DETACH DATABASE " + attachSchema);
}
}
Если у вас есть представления /триггеры / индексы, тогда вышеописанное можно было бы расширить
- было бы лучше всего сделать это, особенно триггеры и индексы, после того, как данные скопированы, так как вы не хотели бы, чтобы триггеры повторно запускали и создавали индексы последанные могут сократить затрачиваемое время.
Копия SQL в основном INSERT INTO diskdb.the_current_tableName SELECT * FROM the_current_tableName
(обратите внимание, что не нужно отключать поддержку внешнего ключа, так какпо умолчанию он выключен).
Пример
Файл базы данных из серии, описанной выше, был скопирован и открыт в Navicat: -
![enter image description here](https://i.stack.imgur.com/PIc19.png)
Пример 2
В этом примере выполняется копирование из существующей копии БД IN MEMORY в БД IN MEMORY, а также копирование на диск базы данных IN MEMORY.и имеет три таблицы: -
Код как действие (поэтому контекст доступен)
: -
public class MainActivity extends AppCompatActivity {
private static final String ATTACH_DBFILE_SCHEMA = "diskdb";
private static final String ATTACH_MASTER_SCHEMA = "main";
private static final String ATTACH_SCHEMA_SEPERATOR = ".";
private static final String SQLITE_MASTER_TABLE = "sqlite_master";
private static final String SQLITE_MASTER_NAME_COLUMN = "name";
private static final String SQLITE_MASTER_TYPE_COLUMN = "type";
private static final String SQLITE_MASTER_SQL_COLUMN = "sql";
private static final String SQLITE_MASTER_TYPE_TABLE = "table";
private static final String SQLITE_SYSTEMDB_PREFIX = "sqlite_";
private static final String ANDROID_METADATA = "android_metadata";
public static final String DISKDBNAME = "mydb";
SQLiteDatabase memorydb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadOrCreateMemoryDB();
//Add some testing data (each time App is run)
memorydb.execSQL("INSERT INTO tablex (name) VALUES ('FRED@' || (datetime('now'))),('MARY'),('JANE')");
memorydb.execSQL("INSERT INTO tabley (name) VALUES ('BERT@' || (datetime('now'))),('SUE'),('TOM')");
memorydb.execSQL("INSERT INTO tablez (name) VALUES ('JOHN@' || (datetime('now'))),('ALEX'),('CHRISTINE')");
//Done so save In Memory DB to file
copyMemoryDBToFileDB();
memorydb.close();
}
/**
* Copy the IN MEMORY DB to file (assumes App's)
*/
private void copyMemoryDBToFileDB() {
File db = new File(getDatabasePath(DISKDBNAME).getPath()); //Path to the disk based backup
// delete the file if it exists and also create directories (i.e. databases directory)
if (db.exists()) {
db.delete();
}
if (!db.getParentFile().exists()) {
db.getParentFile().mkdirs();
}
//Initialise the file as an SQLite database (for Android so it has android_metadata)
SQLiteDatabase dbFile = SQLiteDatabase.openDatabase(db.getPath(), null, SQLiteDatabase.CREATE_IF_NECESSARY);
dbFile.setForeignKeyConstraintsEnabled(false); //<<<<<<<<<< not needed
dbFile.close(); //<<<<<<<<<< close the database so it will be initialised but empty
// Do everything in a single transaction
memorydb.beginTransaction();
// Attach the disk dataabse
memorydb.execSQL("ATTACH DATABASE '" + db.getPath() + "' AS " + ATTACH_DBFILE_SCHEMA);
//Get the tables in the memory DB from the sqlite_master table
Cursor csr = memorydb.query(
ATTACH_MASTER_SCHEMA + "." + SQLITE_MASTER_TABLE,
null,
SQLITE_MASTER_TYPE_COLUMN + "=?",
new String[]{SQLITE_MASTER_TYPE_TABLE},
null, null, null
);
//Iterate through the tables
while (csr.moveToNext()) {
//get the current table and the generate the table to save to in the disk based DB
String currentTable = csr.getString(csr.getColumnIndex("name"));
String dbfileTable = ATTACH_DBFILE_SCHEMA + ATTACH_SCHEMA_SEPERATOR + currentTable;
//Skip system tables (probably ok to skip) and also android_metadata
if (currentTable.startsWith(SQLITE_SYSTEMDB_PREFIX) || currentTable.equals(ANDROID_METADATA))
continue;
//If not a skipped table then create it on disk db, using schema (as attached) and then load it
String crtSQL = csr.getString(csr.getColumnIndex(SQLITE_MASTER_SQL_COLUMN))
.replaceFirst(currentTable, dbfileTable).replaceFirst("CREATE TABLE ", "CREATE TABLE IF NOT EXISTS ");
memorydb.execSQL(crtSQL);
memorydb.execSQL("INSERT INTO " + dbfileTable + " SELECT * FROM " + currentTable);
}
csr.close();
// All done so end the transaction (commit changes)
memorydb.setTransactionSuccessful();
memorydb.endTransaction();
// No longer need to have the database attached and detach it
memorydb.execSQL("DETACH DATABASE '" + ATTACH_DBFILE_SCHEMA + "'");
}
/**
* If a disk database exists then load it into the IN MEMORY DB, else create the In MEMORY DB with tables
*/
private void loadOrCreateMemoryDB() {
// Get the File of the disck based DB
File dbFile = new File(getDatabasePath(DISKDBNAME).getPath());
// Create the In MEMORY DB
memorydb = SQLiteDatabase.create(null);
//If the disk based db exists copy the tables to the In MEMEORY DB
if (dbFile.exists()) {
// Attach the disk based db
memorydb.execSQL("ATTACH DATABASE '" + dbFile.getPath() + "' AS " +ATTACH_DBFILE_SCHEMA);
// Do everything in a single transaction
memorydb.beginTransaction();
// Get the tables in the disk based DB
Cursor csr = memorydb.query(
ATTACH_DBFILE_SCHEMA + ATTACH_SCHEMA_SEPERATOR + SQLITE_MASTER_TABLE,
null,
SQLITE_MASTER_TYPE_COLUMN +"=?",
new String[]{SQLITE_MASTER_TYPE_TABLE},
null,null,null
);
// Iterate through the tables
while (csr.moveToNext()) {
//get the current table tfor the IN MEMORY DB and the table on disk (append Schema)
String currentTable = csr.getString(csr.getColumnIndex(SQLITE_MASTER_NAME_COLUMN));
String dbFileTable = ATTACH_DBFILE_SCHEMA + ATTACH_SCHEMA_SEPERATOR + currentTable;
// Skip system tables and also android_metadata
if (currentTable.startsWith(SQLITE_SYSTEMDB_PREFIX) || currentTable.equals(ANDROID_METADATA))
continue;
// Otherwise create the table based upon the SQL from sqlite_master (should not need IF NOT EXISTS)
memorydb.execSQL(csr.getString(csr.getColumnIndex(SQLITE_MASTER_SQL_COLUMN)));
// Load the data extracted from the disk based table
memorydb.execSQL("INSERT INTO main." + currentTable + " SELECT * FROM " + dbFileTable);
}
// Done with the Cursor
csr.close();
// All done so end the transaction (commit changes)
memorydb.setTransactionSuccessful();
memorydb.endTransaction();
// detach the disk based database
memorydb.execSQL("DETACH DATABASE '" + ATTACH_DBFILE_SCHEMA + "'");
} else {
// No datbase file so just create tables (as required)
memorydb.execSQL("CREATE TABLE tablex (_id INTEGER PRIMARY KEY, name TEXT)");
memorydb.execSQL("CREATE TABLE tabley (_id INTEGER PRIMARY KEY, name TEXT)");
memorydb.execSQL("CREATE TABLE tablez (_id INTEGER PRIMARY KEY, name TEXT)");
}
}
}
Результат
- снимок экрана с Navicat, после 3 прогонов (таким образом, 9 строк в каждой таблице, показаны таблицы)
![enter image description here](https://i.stack.imgur.com/BEBHB.png)