如何将现有的SQLite3数据库导入到Room中?

7

好的,我在桌面上使用了SQLite3创建了一个仅需读取的某些信息的数据库。我正在制作的应用程序不需要向此表中插入或删除信息。

我已经在Google上搜索了Room数据库层的大量文档,其中所有文档都涉及在构建应用程序时在Room中创建一个全新的数据库 - 这不是我想要的,因为我已经有了一个。

我该如何让Room读取已经存在的数据库?我的数据库目前存储在/app/src/main/assets/splitbilldatabase.db中。

2个回答

7
如果您正在使用 Room 2.2.0 或更高版本,您可以配置数据库构建器从 assets 文件夹加载数据库。
Room.databaseBuilder(appContext, AppDatabase.class, "splitbilldatabase.db")
    .createFromAsset("splitbilldatabase.db")
    .build()

更多信息请参见:https://developer.android.com/training/data-storage/room/prepopulate


2

首先,您需要为Room模式创建所有要导入的内容(@Database、@Entity等表格),这些内容必须完全匹配要导入的数据库的模式。

外部数据库文件应该被复制(就像您所做的)到assets文件夹中。

然后,您可以在任何尝试打开Room数据库之前将文件复制,例如在RoomDatabaseinit方法中,但是仅当文件/数据库不存在时才能这样做

以下是一个可行的(但未经过广泛测试的)示例:

@Database(entities = {MyTable.class,
        MyOthertable.class,
        MyMappingTable.class},version = 1,
        exportSchema = false)

public abstract class  MyDatabase extends RoomDatabase {

    public static final String DBNAME = "splitbilldatabase.db";


    public static final String TB_MYTABLE = "mytable";
    public static final String TB_MYOTHERTABLE = "myothertable";
    public static final String TB_MYMAPPINGTABLE = "mymappingtable";

    public static final String COL_MYTABLE_ID = BaseColumns._ID;
    public static final String COL_MYTABLE_NAME = "_name";
    public static final String COL_MYTABLE_DESCRIPTION = "_description";

    public static final String COL_MYOTHERTABLE_ID = BaseColumns._ID;
    public static final String COL_MYOTHERTABLE_OTHERDETAILS = "_otherdetails";

    public static  final String COL_MYMAPPINGTABLE_MYTABLEREFERENCE = "_mytable_reference";
    public static final String COL_MYMAPPINGTABLE_MYOTEHERTABLEREFERENCE = "_myothertable_reference";

    public abstract MyTableDao myTableDao();
    public abstract MyOtherTableDao myOtherTableDao();
    public abstract MyMappingTableDao myMappingTableDao();

    public MyDatabase() {
        super();
    }

    @Override
    public void init(@NonNull DatabaseConfiguration configuration) {
        importExistingDatabase(configuration.context, true); //<<<<<<<<<< Invokes the Import of the Exisiting Database.
        super.init(configuration);
    }

    private void importExistingDatabase(Context context, boolean throw_exception) {
        int buffer_size = 32768;
        File dbpath = context.getDatabasePath(DBNAME);
        if (dbpath.exists()) {
            return; // Database already exists
        }
        // Just in case make the directories
        File dirs = new File(dbpath.getParent());
        dirs.mkdirs();
        int stage = 0;
        byte[] buffer = new byte[buffer_size];
        long total_bytes_read = 0;
        long total_bytes_written = 0;
        int bytes_read = 0;
        try {  
            InputStream assetdb = context.getAssets().open(DBNAME);
            stage++;
            dbpath.createNewFile();
            stage++;
            OutputStream realdb = new FileOutputStream(dbpath);
            stage++;
            while((bytes_read = assetdb.read(buffer)) > 0) {
                total_bytes_read = total_bytes_read + bytes_read;
                realdb.write(buffer,0,bytes_read);
                total_bytes_written = total_bytes_written + bytes_read;
            }
            stage++;
            realdb.flush();
            stage++;
            assetdb.close();
            stage++;
            realdb.close();
            stage++;
        } catch (IOException e) {
            String failed_at = "";
            switch  (stage) {
                case 0:
                    failed_at = "Opening Asset " + DBNAME;
                    break;
                case 1:
                    failed_at = "Creating Output Database " + dbpath.getAbsolutePath();
                    break;
                case 2:
                    failed_at = "Genreating Database OutputStream " + dbpath.getAbsolutePath();
                    break;
                case 3:
                    failed_at = "Copying Data from Asset Database to Output Database. " +
                            " Bytes read=" + String.valueOf(total_bytes_read) +
                            " Bytes written=" + String.valueOf(total_bytes_written);
                    break;
                case 4:
                    failed_at = "Flushing Written Data (" +
                            String.valueOf(total_bytes_written) +
                            " bytes written)";
                    break;
                case 5:
                    failed_at = "Closing Asset Database File.";
                    break;
                case 6:
                    failed_at = "Closing Created Database File.";
            }
            String msg = "An error was encountered copying the Database " +
                    "from the asset file to New Database. " +
                    "The error was encountered whilst :-\n\t" + failed_at;
            Log.e("IMPORTDATABASE",msg);
            e.printStackTrace();
            if (throw_exception) {
                throw new RuntimeException(msg);
            }
        }
    }
}
  • 请注意,假设文件名相同。

那么我不需要为了让Android喜欢它而向数据库添加任何额外的内容吗? - Siku M.
@SikuM 我不这么认为。额外的表(一个用于房间,另一个用于存储区域设置的 android_metadata 表)将由底层代码创建。 - MikeT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接