Android中SQLite预填充数据库复制不完整问题求助
问题排查与解决方案
看起来你遇到的核心问题是复制后的数据库没有被正确加载,反而系统创建了一个空的数据库(只有默认的ID列,没有你定义的nom列和数据)。这大概率是数据库路径不匹配,以及SQLiteOpenHelper的初始化逻辑导致的,下面一步步拆解原因并给出修复方案:
核心问题分析
- 数据库路径错误:你定义的
DB_PATH = context.getApplicationInfo().dataDir + "/"并不是Android系统默认存放数据库的路径。SQLiteOpenHelper默认会把数据库放在/data/data/[包名]/databases/目录下,而你复制的数据库到了dataDir根目录,导致SQLiteOpenHelper找不到你复制的文件,自动创建了一个空的数据库。 getReadableDatabase()的副作用:在复制数据库前调用getReadableDatabase()会触发系统自动创建一个空数据库到默认路径,后续你复制的文件并没有覆盖这个空数据库(因为路径不对),所以最终加载的是那个空库。
修复后的完整代码
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 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 { 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; // 打印默认数据库路径,方便调试 Log.e("Default DB Path", myContext.getDatabasePath(DB_NAME).getAbsolutePath()); } public void createDataBase() throws IOException { boolean dbExist = checkDataBase(); if (!dbExist) { // 关键:不再调用getReadableDatabase(),避免提前创建空数据库 try { copyDataBase(); } catch (IOException e) { throw new Error("Error copying database: " + e.getMessage()); } } } private boolean checkDataBase() { File databasePath = myContext.getDatabasePath(DB_NAME); boolean exists = databasePath.exists(); Log.e("DB Exists", String.valueOf(exists)); return exists; } private void copyDataBase() throws IOException { InputStream myInput = myContext.getAssets().open(DB_NAME); // 使用系统默认的数据库路径作为输出目标 String outFileName = myContext.getDatabasePath(DB_NAME).getAbsolutePath(); // 确保数据库存放目录存在,避免复制时抛出异常 File outFile = new File(outFileName); if (!outFile.getParentFile().exists()) { outFile.getParentFile().mkdirs(); } OutputStream myOutput = new FileOutputStream(outFileName); byte[] buffer = new byte[8192]; // 使用更通用的缓冲区大小 int length; while ((length = myInput.read(buffer)) > 0) { myOutput.write(buffer, 0, length); } myOutput.flush(); myOutput.close(); myInput.close(); Log.e("DB Copied", "Successfully copied to: " + outFileName); } public void openDataBase() throws SQLException { String myPath = myContext.getDatabasePath(DB_NAME).getAbsolutePath(); myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE); } @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) { // 升级时先删除旧数据库,再复制新的预填充库 File dbFile = myContext.getDatabasePath(DB_NAME); if (dbFile.exists()) { dbFile.delete(); } try { copyDataBase(); } catch (IOException e) { e.printStackTrace(); } } } public List<String> getAllMetal(){ List<String> returnList = new ArrayList<>(); // 同时检查表结构和数据,方便调试 String tableInfoQuery = "PRAGMA table_info(Metal)"; String dataQuery = "SELECT * FROM Metal"; SQLiteDatabase db = this.getReadableDatabase(); // 打印表结构到日志 Cursor infoCursor = db.rawQuery(tableInfoQuery, null); if (infoCursor.moveToFirst()){ do { String columnName = infoCursor.getString(1); Log.e("Column Name", columnName); returnList.add(columnName); } while (infoCursor.moveToNext()); } infoCursor.close(); // 打印表数据到日志 Cursor dataCursor = db.rawQuery(dataQuery, null); if (dataCursor.moveToFirst()){ do { Log.e("Metal Data", "ID: " + dataCursor.getInt(0) + ", Nom: " + dataCursor.getString(1)); } while (dataCursor.moveToNext()); } dataCursor.close(); db.close(); return returnList; } }
关键修改说明
- 修正数据库路径:全程使用
myContext.getDatabasePath(DB_NAME)获取系统默认的数据库路径,确保复制的数据库和SQLiteOpenHelper加载的是同一个文件。 - 移除多余的
getReadableDatabase()调用:避免在复制前创建空数据库,直接复制资产中的数据库到正确路径。 - 添加目录创建逻辑:确保存放数据库的
databases目录存在,防止复制时抛出文件不存在的异常。 - 优化
onUpgrade逻辑:升级版本时先删除旧数据库,再复制新的预填充数据库,避免版本冲突。 - 增强调试日志:添加了路径、数据库存在性、复制结果等日志,方便排查问题。
使用注意事项
- 确保
assets目录下的ChiffrageBDD.db文件没有损坏,且格式是SQLite 3.x版本(Android支持的版本)。 - 在使用
DataBaseHelper时,按以下顺序调用方法:try { DataBaseHelper dbHelper = new DataBaseHelper(context); dbHelper.createDataBase(); dbHelper.openDataBase(); List<String> columns = dbHelper.getAllMetal(); // 处理查询结果 } catch (IOException e) { e.printStackTrace(); }
内容的提问来源于stack exchange,提问作者pierre LERICHE
相关产品推荐
相关产品推荐

