SQLite
 sql >> Datenbank >  >> RDS >> SQLite

So lesen Sie die Versionsnummer aus einer Datenbankdatei in Android, die sich im Asset-Ordner befindet

Es gibt keine einzelne Versionsnummer, stattdessen kann die Versionsnummer aus mehreren Werten bestehen.

Vermutlich sprichst du von der user_version die das Android SDK SQLiteOpenHelper verwendet.

Es gibt auch die application_id , die wie die user_version als Benutzervariable verwendet werden kann.

Sie sind bereits auf die SQLite_Version gestoßen, sodass diese abgezinst werden kann.

Es gibt auch die data_version, dies ist wahrscheinlich nicht die Versionsnummer, da sie als Hinweis darauf dienen soll, ob die Datenbankdatei in Echtzeit geändert wurde.

Es gibt auch die schema_version, die Sie wahrscheinlich NICHT verwenden möchten, da Warnung:Der Missbrauch dieses Pragmas kann zu einer Beschädigung der Datenbank führen.

Benutzerversion

Wie bereits gesagt, sprechen Sie wahrscheinlich von der user_version . Das erste, was zu beachten ist, ist, dass es sich um eine benutzergesteuerte Variable/ein Feld handelt, das für die benutzerdefinierte Verwendung zur Verfügung gestellt wird. SQLite verwendet oder ändert die user_version nicht erlaubt aber, dass es geändert und verwendet wird.

Außerdem würden SQLite-Manager (wie DB Browser, Navicat usw.) die Versionsnummer nicht automatisch ändern. Daher müssten Sie die user_version absichtlich ändern, damit sie verfügbar ist, bevor Sie die Datenbankdatei in den Assets-Ordner kopieren (beachten Sie, dass Sie dabei eine Unterklasse von SQLiteOpenHelper verwenden dass das onUpgrade und das onDowngrade Methoden können aufgerufen werden).

Wenn die user_version nicht speziell geändert wurde und auf die Datenbank nur vom SQLite Manager-Tool zugegriffen wurde, ist die user_version 0. Wenn die Datenbankdatei durch Kopieren der Datenbankdatei aus einer Android-App geöffnet wurde, die eine Unterklasse von SQLiteOpenHelper verwendet, hat sie eine user_version von 1 oder mehr (abhängig vom letzten Wert, der als 4. Parameter für den Konstruktor von SQLiteOpenHelper verwendet wird). Wenn die user_version programmgesteuert geändert wird, würde sich eine solche Änderung natürlich auch widerspiegeln, wenn die Datei in ein SQlite Manager-Tool kopiert würde.

Vor dem Kopieren der Datei würde die user_version normalerweise im SQlite Manager-Tool auf einen geeigneten Wert geändert werden.

Sie können die user_version ändern mit dem SQL PRAGMA user_version = 5; Sie können die user_version abrufen entweder mit PRAGMA user_version oder SELECT * FROM pragma_user_version;

Wenn Sie die Version überprüfen müssen, bevor Sie die Datenbank öffnen, können Sie die 4 Bytes bei Offset 60 lesen und die 4 Bytes in eine ganze Zahl konvertieren, um die user_version mit einem anderen Wert zu vergleichen. Andernfalls müssten Sie wahrscheinlich die Datei, wahrscheinlich unter einem anderen Namen, aus dem Assets-Ordner kopieren, sie als SQLiteDatabase öffnen und die user_version mit dem obigen SQL abrufen und sie dann mit dem anderen Wert vergleichen und die Datenbankdatei schließen. Das Löschen der Datei, wenn sie nicht benötigt wird, andernfalls das Löschen der vorherigen Datenbankdatei und das anschließende Umbenennen der kopierten Datei.

Beispiel

Das Folgende ist ein Arbeitsbeispiel (beachte, dass ich selten Kotlin verwende und dies mit AS Studio von Java konvertiert wurde).

Dies verwendet eine Klasse, nämlich SQLAssetVersionCheck die die Versionsnummer aus der Datei extrahiert, anstatt die Datei als SQLiteDatabase zu öffnen.

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
    }
}

Und hier ist eine Aktivität, die die obige Klasse zweimal verwendet, um zu versuchen, die Version in der testdb zu überprüfen Datei.

  • Die erste Verwendung findet die Datenbankdatei testdb nicht wie es in Assets aussieht Ordner (nicht das Unterverzeichnis databases).

  • Die zweite Verwendung findet die testdb Datei als Unterverzeichnis databases angegeben ist (3. Parameter des vollständigen Konstruktors), zu finden in assets/databases/ Ordner, also assets/databases/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")
    }
}

Ergebnis (Protokoll):-

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
  • Der erste Versuch findet die Datei nicht (die abgefangene Ausnahme wird angezeigt) und zeigt die Zeile The result of the version check was - The Asset, for Database testdb was not located at testdb an anzuzeigen.

  • Der zweite Versuch funktioniert und führt zu Das Ergebnis der Versionsprüfung war - Das Asset wurde gefunden und die Versionsnummer 5 war niedriger als die zu prüfende Version 100

  • Die Leerzeilenlücke wurde hinzugefügt, um den zweiten Versuch vom ersten zu trennen.

Zusätzlich

Nach der Verwendung des SQLite Manager-Tools (Navicat) und der Verwendung von :-

PRAGMA user_version = 101;

Kopieren Sie dann die Datei (nach dem Schließen der Verbindung in Navicat) in den Assets-Ordner (also habe ich zwei testdb-Dateien), dann ist das Ergebnis:-

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
  • d.h. die neue Datei hat die user_version als 101 und so findet die erste die Datei, die zweite findet die Datei (user_version 5) wie zuvor.