java - Android Sqlite 数据库复制数据库函数路径

标签 java android kotlin android-sqlite sqliteopenhelper

我正在使用下面的代码来复制 sqlite 数据库,只是想知道路径的正确编码是什么,因为 Android Studio 建议不要对路径进行硬编码,如所附图像所示。这里的大多数答案也使用了硬编码的/data/data 路径。

    companion object {

    private val DATABASE_VERSION = 1
    private val DATABASE_NAME = "books.db"

    @JvmStatic
    fun copyDatabase(context: Context) {

        LogUtil.loge("copyDatabase")
        try {
            var dir = "/data/data/" + context.getPackageName() + "/databases"
            if (Build.VERSION.SDK_INT >= 24){
                dir = context.dataDir.absolutePath + "/databases/"
            }
            if(!File(dir).exists()){
                LogUtil.loge("databases dir not exist")
                File(dir).mkdir()
            }
            val outFileName = context.getDatabasePath(DATABASE_NAME)
            val myOutput = FileOutputStream(outFileName)
            val buffer = ByteArray(1024)
            var length: Int
            val myInput = context.assets.open("databases/$DATABASE_NAME")
            length = myInput.read(buffer)
            while (length > 0) {
                myOutput.write(buffer, 0, length)
                length = myInput.read(buffer)
            }
            myInput.close()
            myOutput.flush()
            myOutput.close()
        } catch (e: IOException) {
            e.printStackTrace()
            LogUtil.loge("unable to copy database")
        }
    }
}

enter image description here

最佳答案

首先使用Context的getDatabasePath("databasename");创建一个File对象,然后使用File的getParentFile将目录获取为文件,然后作为OutputStream的基础。您需要做的就是对数据库名称(以及 Assets 文件夹中的数据库文件夹)进行硬编码。

getDatabasePath

例如类似的东西:-

private fun dbcopy(context: Context) {

    val dbfile = File(context.getDatabasePath(DATABASE_NAME).path)
    if (!dbfile.parentFile.exists()) {
        dbfile.parentFile.mkdirs()
    }
    try {
        val os = FileOutputStream(dbfile)
        // and so on
    } catch (e: IOException) {

    }

}

附注无需检查版本,以上内容适用于我所知道的所有版本(尽管是从 Java 转换而来)。

打开资源时,您需要对数据库进行硬编码,因为它不是标准/预定义/必须使用的文件夹。

我倾向于进行目录检查并创建作为检查数据库是否存在的一部分,例如:-

private fun checkDataBase(context: Context): Boolean {

    val db = File(context.getDatabasePath(DATABASE_NAME).path) //Get the file name of the database
    if (db.exists()) return true // If it exists then return doing nothing

    val dbdir = db.parentFile
    // If the directory does not exist then make the directory (and higher level directories)
    if (!dbdir.exists()) {
        db.parentFile.mkdirs()
        dbdir.mkdirs()
    }
    return false
}

以下是一个完整的帮助程序(减去任何访问数据库的方法),如果数据库不存在,它将从 Assets 数据库文件夹中复制数据库:-

class MyDBHelper(internal var myContext: Context) : SQLiteOpenHelper(myContext, DATABASE_NAME, null, DATABASE_VERSION) {
    internal var buffer_size = 1024 * 4

    init {
        if (!checkDataBase()) {
            copyDataBase()
        }
    }

    override fun onCreate(db: SQLiteDatabase) {}

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {}

    private fun checkDataBase(): Boolean {

        val db = File(myContext.getDatabasePath(DATABASE_NAME).path) //Get the file name of the database
        Log.d("DBPATH", "DB Path is " + db.path) //TODO remove for Live App
        if (db.exists()) return true // If it exists then return doing nothing

        // Get the parent (directory in which the database file would be)
        val dbdir = db.parentFile
        // If the directory does not exits then make the directory (and higher level directories)
        if (!dbdir.exists()) {
            db.parentFile.mkdirs()
            dbdir.mkdirs()
        }
        return false
    }

    private fun copyDataBase() {
        try {

            val myInput = myContext.assets.open("databases" + File.separator + DATABASE_NAME) // Open the Asset file
            val outfile = File(myContext.getDatabasePath(DATABASE_NAME).toString())
            val myOutput = FileOutputStream(outfile)
            //transfer bytes from the inputfile to the outputfile
            val buffer = ByteArray(buffer_size)
            var length = myInput.read(buffer)
            while (length > 0) {
                myOutput.write(buffer, 0, length)
                length = myInput.read(buffer)
            }
            //Close the streams
            myOutput.flush()
            myOutput.close()
            myInput.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    companion object {
        private val DATABASE_NAME = "thedatabase.db"
        private val DATABASE_VERSION = 1
    }
}
  • 请注意,文件分隔符不是硬编码,而是根据系统值获取。

关于java - Android Sqlite 数据库复制数据库函数路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58068172/

相关文章:

android - 将 Firebase 数据快照反序列化为 Kotlin 数据类

java - 检测 url 是否可以使用 HTTP 请求访问

android - CircleCI 中的单元测试因 org.gradle.internal.exceptions.LocationAwareException 而失败

java - Netty 增加 ChannelBuffer 大小

java - Gson反序列化返回一个包含null的Object

android - 形状 XML 中的边框

java - 不幸的是 MyApp 已停止。我该如何解决这个问题?

kotlin - 当我在 Kotlin 中使用委托(delegate)时,MutableMap<String, Any?> 如何将值传递给 var?

java版本 "1.7.0_171"支持密码套件TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

java - 如何检查 List<String> 是否已排序匹配 Guava 中的特定模式?