java - 数据库导入和导出在 Android Pie 中不起作用
问题描述
以下是导入和导出 SQLite 数据库的工作方法。它在除 Android Pie 之外的所有 android 版本中都能正常工作。当我尝试在 Android pie 中导入时,它显示成功 toast 但数据库未恢复。任何人都可以帮助我在 Android Pie(API 28)中解决问题。
private void importDB() {
try {
File sd = Environment.getExternalStorageDirectory();
File cur_db_pat = new File(this.getDatabasePath(DATABASE_NAME).getAbsolutePath());
if (sd.canWrite()) {
String backupDBPath = bac_dir_nam +"/" + DATABASE_NAME;
File currentDB = new File(sd, backupDBPath);
FileChannel src = new FileInputStream(currentDB).getChannel();
FileChannel dst = new FileOutputStream(cur_db_pat).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
Toast.makeText(getBaseContext(), cur_db_pat.toString(),
Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG)
.show();
}
}
private void exportDB() {
try {
File sd = Environment.getExternalStorageDirectory();
File cur_db_pat = new File(this.getDatabasePath(DATABASE_NAME).getAbsolutePath());
if (sd.canWrite()) {
String backupDBPath = bac_dir_nam+"/" + DATABASE_NAME;
File backupDB = new File(sd, backupDBPath);
FileChannel src = new FileInputStream(cur_db_pat).getChannel();
FileChannel dst = new FileOutputStream(backupDB).getChannel();
dst.transferFrom(src, 0, src.size());
src.close();
dst.close();
Toast.makeText(getBaseContext(), backupDB.toString(),
Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG)
.show();
}
}
我对文件系统没有太多经验。所以一个例子会有很大帮助。
解决方案
在 Android Pie+ 中,SQLite 已更改为默认使用通常更高效的预写日志 ( WAL ) 而不是日志模式。
因此,将有两个与数据库同名但后缀为-shm(共享内存文件)和-wal(预写日志)的文件,我认为它们的存在是导致问题的原因。 SQLite 使用的临时文件(见 2.2 和 2.3)
一种解决方法是使用 SQliteDatabase disableWriteAheadLogging方法禁用预写日志记录,之前的方法将像以前一样工作,但日志模式效率较低。
- (如果使用 SQliteOpenHelper 的子类,则覆盖onConfigure方法以调用此方法。)disableWriteAheadLogging。
另一个解决方法是在恢复时删除这两个文件。为了避免潜在的损坏,您必须确保在进行备份之前对数据库进行了充分的检查点。见PRAGMA 检查点;
以下是在还原时删除这两个文件的片段(注意,假定备份已通过足够的检查点进行):-
// Added for Android 9+ to delete shm and wal file if they exist
File dbshm = new File(dbfile.getPath() + "-shm");
File dbwal = new File(dbfile.getPath()+ "-wal");
if (dbshm.exists()) {
dbshm.delete();
}
if (dbwal.exists()) {
dbwal.delete();
}
另一个解决方法是额外备份并随后恢复 -shm 和 -wal 文件。
您可能还希望在导入/恢复时考虑重命名原始文件的潜在好处,在复制新文件后检查它们(例如使用PRAGMA integrity_check;)如果结果表明没有问题,则删除重命名的原始文件,否则删除导入文件并将原文件重命名为原名,表示导入失败。
推荐阅读
- ios - AVAudio - iOS Swift 开发
- reactjs - react redux reducer 中的不变性
- java - JMeter:需要在请求头中发送“Cookie”参数
- azure-devops - 备用凭据 - 如何生成列表
- angular - 如何将角度材料日期选择器日期转换为 UTC 格式?
- php - Woocommerce 获取产品描述
- ios - 为什么我无法构建新的 iPad Xamarin 应用程序?
- flutter - 将按钮动画化为进度指示器
- java - 正确使用 HttpServletResponse response.reset() 以及如何摆脱它
- javascript - cytoscape.js - 如何合并来自不同来源的同一节点的属性