如何从放置在资产文件夹中的Android数据库文件中读取版本号

时间:2019-02-18 06:17:23

标签: android database sqlite kotlin android-sqlite

我在要手动放置的软件包数据库下的资产文件夹中有一个SQLite文件(例如:src-> main-> asset-> databases-> q-db(q-db是我​​的SQLite文件)。 / p>

现在,我想读取其版本号,如果要将此版本放置在我自己的应用程序中,则要进行匹配,如果不存在,则需要将其复制到我的数据库中,否则将跳过。当然,这是第一次从文件复制,而下次每次打开应用程序时,它将检查版本号。

我用Google搜索了很多,但是无法获取文件的版本号,我得到的是我不想使用的SQLite版本号。非常感谢您的支持。

供参考:我正在关注与此类似的人

https://www.concretepage.com/android/android-ship-sqlite-database-with-apk-copy-sqlite-database-from-assets-folder-to-data-example

1 个答案:

答案 0 :(得分:0)

没有单个版本号,而是版本号可以是多个值。

猜测您正在与Android SDK SQLiteOpenHelper使用的 user_version 相邻。

还有 application_id ,它可以像user_version一样用作用户变量。

您已经遇到了SQLite_Version,因此可以打折。

还有data_version,它不太可能是版本号,因为它旨在指示数据库文件是否已实时修改。

也有schema_version,您可能不希望将其用作 警告:滥用此编译指示可能会导致数据库损坏。

user_version

如前所述,您可能正在谈论 user_version 。首先要注意的是,它是一个用户控制的变量/字段,可自定义使用。 SQlite不会使用或更改 user_version ,但允许对其进行更改和使用。

此外,SQLite管理器(例如DB Browser,Navicat等)不会自动更改版本号。因此,在将数据库文件复制到Assets文件夹之前,您必须故意更改user_version使其可用(请注意,如果这样做,并且您正在使用SQLiteOpenHelper的子类,则onUpgrade并且可以调用onDowngrade方法。

如果未专门更改user_version并且仅通过SQLite Manager工具访问该数据库,则它的user_version将为0。如果通过从使用SQLiteOpenHelper子类的Android应用程序复制数据库文件来打开数据库文件,则它的user_version将为1或更大(取决于最后一个值用作SQLiteOpenHelper的构造函数的第4个参数)。当然,如果以编程方式更改了user_version,则如果将文件复制到SQlite Manager工具中,也会反映出这种变化。

在复制文件之前,通常会在SQlite Manager工具中将user_version更改为适当的值。

您可以使用SQL PRAGMA user_version = 5;更改 user_version 您可以使用PRAGMA user_versionSELECT * FROM pragma_user_version;

检索 user_version

如果需要在打开数据库之前检查版本,则可以读取偏移量60处的4个字节并将4个字节转换为整数,以对照另一个值检查user_version。否则,您可能必须从assets文件夹复制文件(可能使用不同的名称),将其作为SQLiteDatabase打开,并使用上述SQL检索user_version,然后对照其他值进行检查,以关闭数据库文件。不需要时删除文件,否则删除先前的数据库文件,然后重命名复制的文件。

示例

以下是一个有效的示例(请注意,我很少使用Kotlin,并且已使用Java的AS Studio对其进行了转换。)

这使用了一个类,即 SQLAssetVersionCheck ,该类从文件中提取版本号,而不是将文件作为SQLiteDatabase打开。

SQLAssetVersionCheck.kt:-

class SQLAssetVersionCheck
/**
 * Full SQLAssetVersionCheck Constructor - sub directories can be specified
 * @param context           Assets are part of package so use the context to get the asset file
 * @param dbName            The database name (i.e. the file name)
 * @param subDirectories    The sub-directories as per the heirarchial order
 * @param dbVersion         The database version to check against
 */
(context: Context, val databaseName: String, subDirectories: Array<String>?, dbVersion: Int) {
    val assetPath: String
    var databaseVersion: Int = 0
        private set
    var result: Int = 0
        private set


    init {
        assetPath = applySubDirectories(databaseName, subDirectories)
        Log.d("SQLAVC", "Looking for Asset $assetPath")
        var stage = 0
        try {
            val `is` = context.assets.open(assetPath)
            stage++
            // Get the first 64 bytes of the header
            val v = ByteArray(64)
            `is`.read(v, 0, 64)
            // only interested in the 4 bytes from offset 60 so get them
            val v2 = ByteArray(4)
            for (i in 60..63) {
                v2[i - 60] = v[i]
            }
            stage++
            // Done with the InputStream so close it
            `is`.close()
            // Extarct the stored DBVersion
            databaseVersion = ByteBuffer.wrap(v2).int
            if (databaseVersion < dbVersion) {
                result = ASSETVERSIONLOW

            }
            if (databaseVersion > dbVersion) {
                result = ASSETVERSIONHIGH
            }
            if (databaseVersion == dbVersion) {
                result = ASSETVERSIONMATCH
            }

        } catch (e: IOException) {
            e.printStackTrace()
            when (stage) {
                0 -> result = ASSETNOTFOUND
                1 -> result = ASSETIOERROR
            }
        }

    }

    constructor(context: Context, dbName: String, dbVersion: Int) : this(context, dbName, null, dbVersion) {}

    private fun applySubDirectories(dbname: String, subDirectories: Array<String>?): String {
        val base = StringBuffer("")
        var firstdirectory = true
        if (subDirectories != null) {
            for (d in subDirectories) {
                if (!firstdirectory) {
                    base.append(File.separatorChar)
                }
                firstdirectory = false
                base.append(d)
            }
        }
        if (base.length > 0) {
            base.append(File.separatorChar)
        }
        base.append(dbname)
        return base.toString()
    }

    companion object {

        val ASSETNOTFOUND = -2
        val ASSETIOERROR = -3
        val ASSETVERSIONMATCH = 0
        val ASSETVERSIONHIGH = 1
        val ASSETVERSIONLOW = -1
    }
}

这是一个Activity,它使用上述类两次来尝试检查 testdb 文件中的版本。

  • 第一次使用时未在 assets 文件夹(不是数据库子目录)中找到数据库文件 testdb

  • 第二种用法是找到 testdb 文件,因为指定了子目录 databases (完整构造函数的第3个参数),在资产/数据库/ 文件夹,即资产/数据库/ testdb :-

MainActivity.kt:-

class MainActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val db_version_to_check_against = 100

        var mAVC1 = SQLAssetVersionCheck(this, "testdb", 100)

        var result = ""
        when (mAVC1.result) {
            SQLAssetVersionCheck.ASSETIOERROR -> result = "IO ERROR detected - check the Log"
            SQLAssetVersionCheck.ASSETNOTFOUND -> result = "The Asset, for Database " + mAVC1.databaseName + " was not located at  " + mAVC1.assetPath
            SQLAssetVersionCheck.ASSETVERSIONHIGH -> result = "The Asset was located and the version number being " +
                    mAVC1.databaseVersion.toString() +
                    " was higher than the version to be checked which was " +
                    db_version_to_check_against.toString()
            SQLAssetVersionCheck.ASSETVERSIONLOW -> result = "The Asset was located and the version number being " +
                    mAVC1.databaseVersion.toString() +
                    " was lower than the version to be checked which was " +
                    db_version_to_check_against.toString()
            SQLAssetVersionCheck.ASSETVERSIONMATCH -> result = "The Asset version and the version to be check ed are the same."
        }
        Log.d("ASSETVERSIONCHECK", "The result of the version check was - $result")

        var mAVC2 = SQLAssetVersionCheck(this, "testdb", arrayOf("databases"), db_version_to_check_against)
        result = ""
        when (mAVC2.result) {
            SQLAssetVersionCheck.ASSETIOERROR -> result = "IO ERROR detected - check the Log"
            SQLAssetVersionCheck.ASSETNOTFOUND -> result = "The Asset, for Database " + mAVC2.databaseName + " was not located at  " + mAVC2.assetPath
            SQLAssetVersionCheck.ASSETVERSIONHIGH -> result = "The Asset was located and the version number being " +
                    mAVC2.databaseVersion.toString() +
                    " was higher than the version to be checked which was " +
                    db_version_to_check_against.toString()
            SQLAssetVersionCheck.ASSETVERSIONLOW -> result = "The Asset was located and the version number being " +
                    mAVC2.databaseVersion.toString() +
                    " was lower than the version to be checked which was " +
                    db_version_to_check_against.toString()
            SQLAssetVersionCheck.ASSETVERSIONMATCH -> result = "The Asset version and the version to be check ed are the same."
        }
        Log.d("ASSETVERSIONCHECK", "The result of the version check was - $result")
    }
}

结果(日志):-

2019-02-19 13:11:34.473 19058-19058/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset testdb
2019-02-19 13:11:34.473 19058-19058/com.example.so54741423assetdbversioning W/System.err: java.io.FileNotFoundException: testdb
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.content.res.AssetManager.nativeOpenAsset(Native Method)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.content.res.AssetManager.open(AssetManager.java:744)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.content.res.AssetManager.open(AssetManager.java:721)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at com.example.so54741423assetdbversioning.SQLAssetVersionCheck.<init>(SQLAssetVersionCheck.kt:31)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at com.example.so54741423assetdbversioning.SQLAssetVersionCheck.<init>(SQLAssetVersionCheck.kt:67)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at com.example.so54741423assetdbversioning.MainActivity.onCreate(MainActivity.kt:17)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.Activity.performCreate(Activity.java:7136)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.Activity.performCreate(Activity.java:7127)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:106)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.os.Looper.loop(Looper.java:193)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6669)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset, for Database testdb was not located at  testdb




2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset databases/testdb
2019-02-19 13:11:34.477 19058-19058/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset was located and the version number being 5 was lower than the version to be checked which was 100
  • 首次尝试找不到文件(显示捕获的异常),并显示行版本检查的结果是-数据库testdb的资产不在testdb上显示。

  • 第二次尝试成功并导致版本检查的结果是-找到资产,并且版本号5低于要检查的版本100 < / p>

  • 添加了空格行以将第二次尝试与第一次尝试分开。

其他

使用SQLite Manager工具(Navicat)并使用:-

PRAGMA user_version = 101;

然后将文件(在Navicat中关闭连接后)复制到资产文件夹(所以我有两个testdb文件),那么结果是:-

2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset testdb
2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset was located and the version number being 101 was higher than the version to be checked which was 100
2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset databases/testdb
2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset was located and the version number being 5 was lower than the version to be checked which was 100
  • 即新文件的user_version为101,因此第一个找到文件,第二个找到文件(user_version 5)。