我正在尝试将数据库文件从资产文件夹复制到设备/ data / data文件夹中,以供应用程序参考。此复制过程不断失败。
我已经使用了copyDatabase()方法,该方法在关于stackoverflow的类似问题的答案中找到了。这些方法使用由context()。getAssets()。open(databaseName);设置的InputStream变量。但是,就我而言,此分配无法填充数据库。查询数据库的后续方法将引发异常,因为数据库没有按预期的方式存在“主”表。
这是我的copyDatabase()方法:
String DATABASE_NAME = "birdsDBase3.db"
private void copyDatabase(String DATABASE_PATH){
Log.i(TAG, "now in copyDatabase()");
try {
Log.i(TAG, "trying to copy database.");
InputStream assetDB = context.getAssets().open(DATABASE_NAME);
Log.i(TAG, assetDB.toString());
OutputStream appDataBase = new FileOutputStream(DATABASE_PATH, false);
byte[] buffer = new byte[1024];
int length;
while ((length = assetDB.read(buffer)) > 0){
appDataBase.write(buffer, 0, length);
}
appDataBase.flush();
appDataBase.close();
assetDB.close();
} catch(IOException e){
e.printStackTrace();
}
}
}
日志错误:“ SQLiteLog:(1)没有这样的表:类别”
我希望数据库复制到设备上,以便另一种方法可以在一个列中发送针对不同元组的查询。相反,由于数据库中没有“主”表,因此该方法失败。我知道查询的格式正确,因为我已经在SQLite浏览器中运行了该查询并获得了预期的结果,并且该方法已在stackoverflow的另一个线程中进行了检查。
答案 0 :(得分:2)
假设问题很简单,即尚未正确保存数据库(不是罕见的情况,因此请检查并再次检查复制到assets文件夹中的文件是否已相应填充),则可能的问题如下:-< / p>
自从Android 9出现以来,许多从资产文件夹复制数据库的较旧方法现在都失败了。这是由于使用 getWritableDatabase 方法创建了将数据库复制到的数据库文件夹。
即安装了应用程序后,将为应用程序的数据创建文件夹 data / data / package 。默认情况下,SQlite数据库存储在 / data / data / package / database 中,如果数据库文件夹不存在,则复制将失败,并显示 NOENT 。
在创建数据库时,使用SQLiteOpenHelper的 getWritableDatabase 将创建 databases 文件夹,通常与要从资产文件夹复制的数据库的名称/文件相同以及最终的数据库名称。
在Android 9之前,使用的默认日志记录为日记模式。此模式使用与数据库名称相同但后缀-journal的文件。该文件包含交易,可用于从实际数据库回滚交易。
在Android 9中,默认使用预写日志记录(WAL)。这会将实际事务写入文件 -wal (实际上是数据库的一部分,首先查看),并且在发生检查点时更新数据库文件并清除-wal文件。>
因此-wal文件是内部文件,如果存在,则它必须属于为其创建数据库的数据库。
所以发生的事情是getWritableDatabase创建了一个数据库,并且某些事务(例如创建android_metadata表)被写入了-wal文件。从资产文件复制数据库,覆盖新创建的数据库,但-wal和-shm文件(WAL使用的共享内存文件)保留。当打开数据库时,由于-wal和-shm文件不属于复制的数据库,该错误导致数据库无法使用,并且SDK / API创建了可用的新数据库,因此资产文件中不存在任何表已被复制。
解决方案可以是:-
通过在使用数据库之前调用SQLiteDatabase的disableWriteAheadLogging方法来禁用WAL。
使用不同的数据库名称来创建数据库文件夹(尚不知道该怎么做)。
在打开复制的数据库之前删除或重命名-wal和-shm文件。
使用标准/基本文件处理(即使用the_databases_parent_file.mkdirs();
在检查数据库文件是否存在时使用此技术的示例是:-
private boolean checkDataBase(Context context, String databaseName) {
/**
* Does not open the database instead checks to see if the file exists
* also creates the databases directory if it does not exists
* (the real reason why the database is opened, which appears to result in issues)
*/
File db = new File(context.getDatabasePath(databaseName).getPath()); //Get the file name of the database
Log.d("DBPATH","DB Path is " + db.getPath()); //TODO remove for Live App
if (db.exists()) return true; // If it exists then return doing nothing
// Get the parent (directory in which the database file would be)
File dbdir = db.getParentFile();
// If the directory does not exits then make the directory (and higher level directories)
if (!dbdir.exists()) {
db.getParentFile().mkdirs();
dbdir.mkdirs();
}
return false;
}
要阻止上述情况,您将使用上述方法检查数据库并取消在检查数据库和调用 copyDatbase 方法之间调用的 getWritableDatabase 。 / p>
答案 1 :(得分:0)
您需要实施
SqliteAssetHelper
在网络上搜索并尝试。