Java Android 复制的数据库不完整
Java Android copied database is incomplete
我正在尝试使用 SQLite 数据库,它是一个已经填满的数据库,经过一些研究我发现我需要复制这个数据库才能使用它,所以我拿起代码并测试了它但是副本不完整,所有列都未复制,数据不存在。当我用 DB Browser for SQLite 打开原始文件时没有问题。
这里是framework databasehelper的代码:
package com.example.chiffrage;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import android.widget.TextView;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
public class DataBaseHelper extends SQLiteOpenHelper {
String DB_PATH = null;
private static String DB_NAME = "ChiffrageBDD.db";
private SQLiteDatabase myDataBase;
private final Context myContext;
public DataBaseHelper(Context context) {
super(context, DB_NAME, null, 10);
this.myContext = context;
this.DB_PATH = context.getApplicationInfo().dataDir + "/";
Log.e("Path 1", DB_PATH);
}
public void createDataBase() throws IOException {
boolean dbExist = checkDataBase();
if (dbExist) {
} else {
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
private boolean checkDataBase() {
// SQLiteDatabase checkDB = null;
// try {
// String myPath = DB_PATH + DB_NAME;
// checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
// } catch (SQLiteException e) {
// }
// if (checkDB != null) {
// checkDB.close();
// }
// return checkDB != null ? true : false;
File databasePath = myContext.getDatabasePath(DB_NAME);
return databasePath.exists();
}
private void copyDataBase() throws IOException {
InputStream myInput = myContext.getAssets().open(DB_NAME);
String outFileName = DB_PATH + DB_NAME;
OutputStream myOutput = new FileOutputStream(outFileName);
byte[] buffer = new byte[2068];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
}
public void openDataBase() throws SQLException {
String myPath = DB_PATH + DB_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
}
@Override
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion > oldVersion)
try {
copyDataBase();
} catch (IOException e) {
e.printStackTrace();
}
}
public List getAllMetal(){
List returnList = new ArrayList();
String queryString = "PRAGMA table_info(Metal)";
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(queryString, null);
if (cursor.moveToFirst()){
do {
returnList.add(cursor.getString(1));
} while (cursor.moveToNext());
} else {
//failure
}
cursor.close();
db.close();
return returnList;
}
}
getAllMetal 的响应是“[ID]”
我应该有一个 table 名称“Metal”,带有“id”和“nom”
nom 是金属的名称。
没有数据,我使用 PRAGMA 验证该列,如您所见,缺少“nom”列。
这里是我获得代码的一些资源:
[复制数据库]
Getting "Failed to open database" error when copying a sqlite database from assets In Android 4.2
时间不多了。
如果 table 不存在,使用 PRAGMA table_info(Metal)
不会失败。相反,它不会显示任何行。因此它可能会产生误导,也可能会误导您。
它显示的是数据库本身存在。但是,仅仅因为数据库存在并不意味着副本本身有效。由于您只显示数据库助手,而不显示实例的用途,因此可能存在各种问题。
我怀疑您遇到了问题并且无意中创建了一个空的数据库(就用户定义的 tables 而言)。这将允许您调用 getAllMetal
并获得您所说的结果。
另一个问题是 DB_PATH 根据使用 this.DB_PATH = context.getApplicationInfo().dataDir + "/";
将与 File databasePath = myContext.getDatabasePath(DB_NAME);
不同。他们将是
- /data/data/
/ChiffrageBDD.db 和
- /data/data/
/databases/ChiffrageBDD.db
反映使用的包名称
使用 Android 很容易意外创建空数据库,因此我怀疑空数据库的存在是您的问题。一旦创建,数据库就会持续存在(除非您专门删除它,否则它始终存在)这也可能是问题的一部分。
不知道你迄今为止所做的一切,也不知道你如何使用 DataBaseHelper
实例,这只是对原因的猜测。
您的 DataBaseHelper
确实存在问题,因为它不适合全新安装的应用程序。安装应用程序时,/data/data/ 目录存在,但数据库目录不存在。 copyDataBase
方法将失败,因为数据库目录不存在。
这是一个可用的数据库助手,您可能希望比较它与您正在使用的工具之间的差异。它们很微妙但很重要:-
public class DBAssetHelper2 extends SQLiteOpenHelper {
static String DATABASE_NAME = "databasefile2";
public DBAssetHelper2(Context context) {
super(context, DATABASE_NAME, null, 1);
String databasePath = context.getDatabasePath(DATABASE_NAME).getPath();
if (!doesDatabaseExist(databasePath)) {
copyDatabaseFromAssets(context,databasePath,DATABASE_NAME);
}
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
// Checks to see if the database exists, if it does not
// then checks to see if the directories in the path exist
// and then makes the directories if they do not
private boolean doesDatabaseExist(String databasepath) {
if (new File(databasepath).exists()) return true;
if (new File(databasepath).getParentFile().exists()) return false;
new File(databasepath).getParentFile().mkdirs();
return false;
}
private void copyDatabaseFromAssets(Context context, String databasepath, String assetfilename) {
int bSize = 4096, bytes = 0;
byte[] buffer = new byte[bSize];
try {
InputStream asset = context.getAssets().open(assetfilename);
FileOutputStream database = new FileOutputStream(new File(databasepath));
while((bytes = asset.read(buffer)) > 0) {
database.write(buffer,0,bytes);
}
database.flush();
database.close();
asset.close();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Error copying Asset File " + assetfilename + " to " + databasepath);
}
}
}
首先,当您创建助手的实例时,它会检查数据库,如果需要,还会检查资产的副本。也就是说,无需调用任何方法来复制数据库(使用您的助手,您需要调用 createDataBase
方法)。
如果您还查看 doesDatabaseExist
方法,您会发现如果数据库文件不存在,则会进一步检查路径中的目录是否存在,如果不存在,则会丢失目录。
异常处理是不可或缺的,如果复制失败并出现 运行 时间异常。
您可能希望相应地修改您的 DataBaseHelper
class 或者您可以复制并使用上面的代码(您显然必须进行一些更改,例如数据库名称)。
重要
完成建议的更改后,您必须 删除现有的(可能是空的)数据库。最简单的方法是卸载应用程序,然后 运行 应用程序。
以下是您可以在 Activity 中使用上述内容的示例:-
public class MainActivity extends AppCompatActivity {
DBAssetHelper2 dbAssetHelper2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbAssetHelper2 = new DBAssetHelper2(this);
Cursor cursor2 = dbAssetHelper2.getReadableDatabase().query("sqlite_master",null,null,null,null,null,null);
DatabaseUtils.dumpCursor(cursor2);
cursor2.close();
}
}
请注意,实例化后的代码从 sqlite_master table 中提取所有行,因此将显示数据库中的所有 table。输出将显示在日志中。
我正在尝试使用 SQLite 数据库,它是一个已经填满的数据库,经过一些研究我发现我需要复制这个数据库才能使用它,所以我拿起代码并测试了它但是副本不完整,所有列都未复制,数据不存在。当我用 DB Browser for SQLite 打开原始文件时没有问题。
这里是framework databasehelper的代码:
package com.example.chiffrage;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import android.widget.TextView;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
public class DataBaseHelper extends SQLiteOpenHelper {
String DB_PATH = null;
private static String DB_NAME = "ChiffrageBDD.db";
private SQLiteDatabase myDataBase;
private final Context myContext;
public DataBaseHelper(Context context) {
super(context, DB_NAME, null, 10);
this.myContext = context;
this.DB_PATH = context.getApplicationInfo().dataDir + "/";
Log.e("Path 1", DB_PATH);
}
public void createDataBase() throws IOException {
boolean dbExist = checkDataBase();
if (dbExist) {
} else {
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
private boolean checkDataBase() {
// SQLiteDatabase checkDB = null;
// try {
// String myPath = DB_PATH + DB_NAME;
// checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
// } catch (SQLiteException e) {
// }
// if (checkDB != null) {
// checkDB.close();
// }
// return checkDB != null ? true : false;
File databasePath = myContext.getDatabasePath(DB_NAME);
return databasePath.exists();
}
private void copyDataBase() throws IOException {
InputStream myInput = myContext.getAssets().open(DB_NAME);
String outFileName = DB_PATH + DB_NAME;
OutputStream myOutput = new FileOutputStream(outFileName);
byte[] buffer = new byte[2068];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
}
public void openDataBase() throws SQLException {
String myPath = DB_PATH + DB_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
}
@Override
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion > oldVersion)
try {
copyDataBase();
} catch (IOException e) {
e.printStackTrace();
}
}
public List getAllMetal(){
List returnList = new ArrayList();
String queryString = "PRAGMA table_info(Metal)";
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(queryString, null);
if (cursor.moveToFirst()){
do {
returnList.add(cursor.getString(1));
} while (cursor.moveToNext());
} else {
//failure
}
cursor.close();
db.close();
return returnList;
}
}
getAllMetal 的响应是“[ID]” 我应该有一个 table 名称“Metal”,带有“id”和“nom” nom 是金属的名称。 没有数据,我使用 PRAGMA 验证该列,如您所见,缺少“nom”列。
这里是我获得代码的一些资源:
[复制数据库] Getting "Failed to open database" error when copying a sqlite database from assets In Android 4.2
时间不多了。
如果 table 不存在,使用 PRAGMA table_info(Metal)
不会失败。相反,它不会显示任何行。因此它可能会产生误导,也可能会误导您。
它显示的是数据库本身存在。但是,仅仅因为数据库存在并不意味着副本本身有效。由于您只显示数据库助手,而不显示实例的用途,因此可能存在各种问题。
我怀疑您遇到了问题并且无意中创建了一个空的数据库(就用户定义的 tables 而言)。这将允许您调用 getAllMetal
并获得您所说的结果。
另一个问题是 DB_PATH 根据使用 this.DB_PATH = context.getApplicationInfo().dataDir + "/";
将与 File databasePath = myContext.getDatabasePath(DB_NAME);
不同。他们将是
- /data/data/
/ChiffrageBDD.db 和 - /data/data/
/databases/ChiffrageBDD.db 反映使用的包名称
使用 Android 很容易意外创建空数据库,因此我怀疑空数据库的存在是您的问题。一旦创建,数据库就会持续存在(除非您专门删除它,否则它始终存在)这也可能是问题的一部分。
不知道你迄今为止所做的一切,也不知道你如何使用 DataBaseHelper
实例,这只是对原因的猜测。
您的 DataBaseHelper
确实存在问题,因为它不适合全新安装的应用程序。安装应用程序时,/data/data/copyDataBase
方法将失败,因为数据库目录不存在。
这是一个可用的数据库助手,您可能希望比较它与您正在使用的工具之间的差异。它们很微妙但很重要:-
public class DBAssetHelper2 extends SQLiteOpenHelper {
static String DATABASE_NAME = "databasefile2";
public DBAssetHelper2(Context context) {
super(context, DATABASE_NAME, null, 1);
String databasePath = context.getDatabasePath(DATABASE_NAME).getPath();
if (!doesDatabaseExist(databasePath)) {
copyDatabaseFromAssets(context,databasePath,DATABASE_NAME);
}
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
// Checks to see if the database exists, if it does not
// then checks to see if the directories in the path exist
// and then makes the directories if they do not
private boolean doesDatabaseExist(String databasepath) {
if (new File(databasepath).exists()) return true;
if (new File(databasepath).getParentFile().exists()) return false;
new File(databasepath).getParentFile().mkdirs();
return false;
}
private void copyDatabaseFromAssets(Context context, String databasepath, String assetfilename) {
int bSize = 4096, bytes = 0;
byte[] buffer = new byte[bSize];
try {
InputStream asset = context.getAssets().open(assetfilename);
FileOutputStream database = new FileOutputStream(new File(databasepath));
while((bytes = asset.read(buffer)) > 0) {
database.write(buffer,0,bytes);
}
database.flush();
database.close();
asset.close();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Error copying Asset File " + assetfilename + " to " + databasepath);
}
}
}
首先,当您创建助手的实例时,它会检查数据库,如果需要,还会检查资产的副本。也就是说,无需调用任何方法来复制数据库(使用您的助手,您需要调用 createDataBase
方法)。
如果您还查看 doesDatabaseExist
方法,您会发现如果数据库文件不存在,则会进一步检查路径中的目录是否存在,如果不存在,则会丢失目录。
异常处理是不可或缺的,如果复制失败并出现 运行 时间异常。
您可能希望相应地修改您的 DataBaseHelper
class 或者您可以复制并使用上面的代码(您显然必须进行一些更改,例如数据库名称)。
重要 完成建议的更改后,您必须 删除现有的(可能是空的)数据库。最简单的方法是卸载应用程序,然后 运行 应用程序。
以下是您可以在 Activity 中使用上述内容的示例:-
public class MainActivity extends AppCompatActivity {
DBAssetHelper2 dbAssetHelper2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbAssetHelper2 = new DBAssetHelper2(this);
Cursor cursor2 = dbAssetHelper2.getReadableDatabase().query("sqlite_master",null,null,null,null,null,null);
DatabaseUtils.dumpCursor(cursor2);
cursor2.close();
}
}
请注意,实例化后的代码从 sqlite_master table 中提取所有行,因此将显示数据库中的所有 table。输出将显示在日志中。