Android:从资产文件夹复制数据库,但只获取一个空文件
伙计们,我在将数据库从本地资产文件夹复制到/data/data/package\u name/databases目录时遇到了问题。当我使用教程来做这件事时,我只能得到一个空文件 我引用了copyDataBase()方法的一部分,没有区别。每次应用程序启动时,它都会创建目录和空数据库。那么有没有办法让copyDataBase()工作呢 非常感谢 我不会从Android:从资产文件夹复制数据库,但只获取一个空文件,android,sqlite,android-assets,Android,Sqlite,Android Assets,伙计们,我在将数据库从本地资产文件夹复制到/data/data/package\u name/databases目录时遇到了问题。当我使用教程来做这件事时,我只能得到一个空文件 我引用了copyDataBase()方法的一部分,没有区别。每次应用程序启动时,它都会创建目录和空数据库。那么有没有办法让copyDataBase()工作呢 非常感谢 我不会从资产-文件夹复制任何数据库。如果数据库中需要一些标准条目,可以使用onCreate()-方法中的INSERTs添加它们 更新:因为这被认为是错误
资产
-文件夹复制任何数据库。如果数据库中需要一些标准条目,可以使用onCreate()
-方法中的INSERT
s添加它们
更新:因为这被认为是错误的(有点正确),我不能删除它,所以这里有一个小的更新 我想说,这取决于要添加到数据库中的标准条目的数量。如果只是一个或两个,运送打包的DB可能不值得 无论如何,有些应用程序附带了相当大的数据库(例如,配方集合)。显然,您不能在代码中添加所有这些内容
- 对于小的测试条目,我仍然更喜欢简单地将它们添加到
中onCreate()
- 对于更大的数据库,您应该预先填充它们,并将它们与应用程序一起发布
为了使以后的工作正常,您需要将数据库文件从
assets/
复制到您的应用程序文件夹中。有一个很好的库可以为您处理这个问题:为什么不从资产中复制?这样做是完全正常的。但是不能在onCreate中执行此操作,此时已经创建了一个空数据库。你需要事先做这件事。我通常在覆盖getWriteableDatabase时这样做,比如
public synchronized SQLiteDatabase getWritableDatabase() {
SQLiteDatabase db = null;
if (!doesDatabaseExist()) {
try {
copyDatabase();
db = super.getWritableDatabase();
} catch(Exception ex) {
Log.e("Database Log", getDatabasePath() + " failed to copy correctly. " + ex.getLocalizedMessage());
}
}
else {
db = super.getWritableDatabase();
}
return db;
}
在右上方的示例中,我的工作方式如下:
db = super.getWritableDatabase();
db.close;
copyDatabase();
否则我会得到一个IO错误 以下是我使用的简单方便的代码:
public class DataBaseImportHelper {
private DataBaseImportHelper() {}; // Avoid instantiation
/**
* Creates a empty database on the system and rewrites it with your own database.
*/
public static boolean importDataBase(Context context) {
InputStream myInput = null;
OutputStream myOutput = null;
try {
// Open local db from assets as the input stream
myInput = context.getAssets().open(DATABASE_NAME);
createEmptyDatabase(context); // See this method below
// Open the empty db as the output stream
myOutput = new FileOutputStream(getDatabaseFile(context));
// transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
// Close the streams
myOutput.flush();
myInput.close();
myOutput.close();
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
/**
* Check if the database already exists.
* @return true if it exists, false if it doesn't
*/
public static boolean isDatabaseExists(Context context) {
return getDatabaseFile(context).exists();
}
private static File getDatabaseFile(Context context) {
return context.getDatabasePath(DatabaseHelper.DATABASE_NAME);
}
/**
* Create an empty database into the default application database
* folder.So we are gonna be able to overwrite that database with our database
*/
private static void createEmptyDatabase(Context context) {
// use anonimous helper to create empty database
new SQLiteOpenHelper(context, DatabaseHelper.DATABASE_NAME, null, 1) {
// Methods are empty. We don`t need to override them
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
@Override
public void onCreate(SQLiteDatabase db) {
}
}.getReadableDatabase().close();
}
}
并在代码中使用:
if(!DataBaseImportHelper.isDatabaseExists(this)){
if (!DataBaseImportHelper.importDataBase(this)){
throw new IllegalStateException("Database doesn`t exist and hasn`t been copied!");
}
}
我不知道它是否仍然有用,但这里有一个解决方案,供其他来到这里观看awnser的人使用。您使用的代码适用于大多数手机,一些较旧的手机在getReadableDatabase()函数中有不同的行为。因此,问题不在于copyDataBase函数,而在于createDataBase函数 在createDataBase()中有以下检查:
this.getReadableDatabase();
这将检查是否已经存在具有所提供名称的数据库,如果没有,将创建一个空数据库,以便可以使用资产文件夹中的数据库覆盖该数据库。在较新的设备上,这可以完美地工作,但也有一些设备无法工作。主要是老式设备。我不知道确切的原因,但getReadableDatabase()函数似乎不仅可以获取数据库,还可以打开它。如果您随后将数据库从资产文件夹复制到它上面,它仍然有指向空数据库的指针,并且您将得到表不存在错误
因此,为了使其在所有设备上工作,您应该将其修改为以下行:
SQLiteDatabase db = this.getReadableDatabase();
if (db.isOpen()){
db.close();
}
即使在检查中打开了数据库,之后它也会关闭,不会给您带来任何麻烦。谢谢!这只是两个小时的工作。:)为什么不从资产中复制db文件?在我的例子中,它是一个R/O数据库,有19个表和35k行insert语句。我看不出为什么要在设备上初始化这样的数据库。是否有我遗漏的内容?是否有不需要复制到数据文件夹的方法?我们可以直接从资产文件夹中读取吗?您的数据库有多大?可能是我的作品(安卓2.3.3)。干净坚实。我必须对它做一点修改:
如果(!doesDatabaseExist()){try{SQLiteDatabase db=super.getReadableDatabase();db.close();}catch(异常忽略){}copyFromAssets();return super.getReadableDatabase();}
否则它会因FileNotFoundException而崩溃,可能是因为数据库目录不存在。(Android 2.2)关键是调用createEmptyDatabase()。如果不这样做,对“new FileOutputStream()”的调用将失败,即使该文件不存在时应该创建该文件。