如何更改Room数据库的默认文件存储位置?

6

我在我的应用程序中使用RoomDB,可以执行crud操作。实际上,我想查看数据库文件。

getDatabasePath("user.db").getAbsolutePath();

上述代码给出了数据库文件所在的目录 目录形如:

 /data/data/com.example.manvish.roomdb/databases/user.db

但是即使我使用命令提示符中的sudo,仍然无法访问数据目录。 现在我想将DB文件位置更改为内部存储器或SD卡中的其他文件夹。我该怎么做?


没有理由复制到外部文件夹。Room 应该只从内部应用程序存储器读取。如果您需要一个外部 SQLite 文件来为您的应用程序提供支持,则需要使用 SQLiteOpenHelper,据我所知。如果您只想查看内容,我已经向您提供了此链接 https://dev59.com/s1cP5IYBdhLWcg3wa5XQ - OneCricketeer
@cricket_007 我想直接修改数据库,使用SQLite浏览器向表中添加一些虚拟数据,而不仅仅是查看。 - Gaju Kollur
好的,我没有找到任何参考资料表明外部SQLite文件不能被读取或导入到Room中,如果你找到了方法,请随时告诉我。 - OneCricketeer
你做完了吗? - M.Yogeshwaran
@M.Yogeshwaran 不,不是。 - Gaju Kollur
显示剩余2条评论
4个回答

4

Java解决方案:

  1. 在Manifest中授予权限
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  1. 创建数据库(在这里SofDatabase是一个单例类)
private static final String DB_NAME = "stack_overflow_db";
private static final String DB_PATH = String.format("%s/%s",
 Environment.getExternalStorageDirectory().getAbsolutePath(), DB_NAME);

    public static synchronized SofDatabase getInstance(Context aContext) {
        if (sInstance == null) {
            sInstance = Room.databaseBuilder(aContext, SofDatabase.class, DB_PATH)
                    .fallbackToDestructiveMigration()
                    .addCallback(roomCallback).build(); //adding callback from Room
        }
        return sInstance;
    }

回调函数
     /**
     * Get Notified once db is created
     */
    private static final RoomDatabase.Callback roomCallback = new RoomDatabase.Callback() {
        @Override
        public void onCreate(@NonNull SupportSQLiteDatabase db) {
            super.onCreate(db);
            Log.i("SOF", db.getPath()); //which prints out -->  I/SOF: /storage/emulated/0/stack_overflow_db
            // add some jobs once db is created
        }
    };

2

要更改数据库位置,只需在构建Room数据库时放置路径,例如,在您的文件夹中,位于内部存储器中的数据库:

最初的回答:

To change the db location just put the path when you build the Room database, an example for a db in your folder, in the internal storage:

fun getDatabase(context: Context, scope: CoroutineScope):   TestDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance =
                    Room.databaseBuilder(
                        context.applicationContext,
                        TestDatabase::class.java,
                        Environment.getExternalStorageDirectory().absolutePath + "/yourFolder/yourdb"
                    ).build()
                INSTANCE = instance
                return instance
            }
        }

这是一个 Kotlin 的示例,如果您需要 Java 版本的,请告诉我。 祝好。

3
对我来说不起作用 --> java.lang.IllegalArgumentException:文件storage/sdcard0/Download/database/example包含路径分隔符。使用的Room版本为1.1.1。在一部华为P8 Lite上。 - marcos E.

1

大家好,我发表我的解决方案是因为我在这个问题上卡了几个小时,几乎认为我们不能使用位于应用程序 "/data/data" 内部目录以外的数据库。

然而,解决方案非常简单。使用下面的代码,我们会遇到 IllegalArgumentException 异常:"文件 ... 包含路径分隔符"

private fun buildDatabase(context: Context) : RMSRoomDatabase {

        val packageName: String = context.getApplicationInfo().packageName
        var path = "sdcard/Android/data/$packageName/files/rms_database.sqlite"

        var builder = Room.databaseBuilder(
            context,
            RMSRoomDatabase::class.java,
            path
        )

        return builder.allowMainThreadQueries()
            .fallbackToDestructiveMigration()
            .build()
    }

但只需将路径更改为以斜杠作为第一个字符,所有内容就可以正常工作!

var path = "/sdcard/Android/data/$packageName/files/rms_database.sqlite"

-1

不确定这是否是您要找的,但在我的情况下,就像@M.Yogeshwaran一样,我需要能够设置数据库的初始状态并从那里开始工作,所以我最终做了这个:

/**
 * @param context
 */
public DatabaseService(Context context) {

        File dst = context.getDatabasePath(DB_NAME);
        dst.delete();
        File src = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()+"/database.db");
        try {
            copy(src,dst);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Init the database singleton
        db = Room.databaseBuilder(context, CrediforceDatabase.class, Constants.DB_NAME).build();
}

public static void copy(File src, File dst) throws IOException {
    try (InputStream in = new FileInputStream(src)) {
        try (OutputStream out = new FileOutputStream(dst)) {
            // Transfer bytes from in to out
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
        }
    }
}

为了更清晰地说明:

  1. DB_NAME = "database.db"
  2. 出于测试目的,我将要“导入”的“database.db”文件放在我的下载文件夹中,稍后我将转换此代码,以便设备从服务器拉取初始数据库。
  3. dst.delete(); 只是为了删除现有的数据库文件,因为我正在测试一些东西(不确定是否需要)
  4. 这基本上可以翻译为:启动应用程序 > 替换数据库文件 > 构建数据库。
  5. 必须小心room_master_table中的identity_hash,如果与预期不同,则无法正常工作。

此外,我从以下答案中提取了这个想法: https://dev59.com/eVcP5IYBdhLWcg3whaUD#50383879

希望它能帮助任何人!

P.S. 如果您只需要查看数据并执行CRUD操作,您始终可以使用此插件:https://github.com/amitshekhariitbhu/Android-Debug-Database


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