SQLite
 sql >> Base de données >  >> RDS >> SQLite

Comment lire le numéro de version d'un fichier de base de données dans Android qui est placé dans le dossier d'actifs

Il n'y a pas un seul numéro de version, à la place le numéro de version peut être plusieurs valeurs.

À deviner, vous parlez de la user_version que le SDK Android SQLiteOpenHelper utilise.

Il y a aussi le application_id , qui, comme user_version, peut être utilisée comme variable utilisateur.

Vous avez déjà rencontré la SQLite_Version, cela peut donc être réduit.

Il y a aussi le data_version, il est peu probable qu'il s'agisse du numéro de version, car il est destiné à être utilisé comme une indication si le fichier de base de données a été modifié en temps réel.

Il y a aussi la schema_version, vous ne voulez probablement PAS l'utiliser comme Attention :une mauvaise utilisation de ce pragma peut entraîner une corruption de la base de données.

version_utilisateur

Comme dit précédemment, vous parlez probablement de la user_version . La première chose à noter est qu'il s'agit d'une variable/champ contrôlé par l'utilisateur mis à disposition pour une utilisation personnalisée. SQlite n'utilise ni ne modifie la user_version mais permet de le modifier et de l'utiliser.

De plus, les gestionnaires SQLite (tels que DB Browser, Navicat, etc.) ne modifieraient pas automatiquement le numéro de version. En tant que tel, vous devrez modifier intentionnellement la user_version pour qu'elle soit disponible avant de copier le fichier de base de données dans le dossier assets (en notant que si vous le faites et que vous utilisez une sous-classe de SQLiteOpenHelper que le onUpgrade et le onDowngrade méthodes peuvent être appelées).

Si la user_version n'est pas spécifiquement modifiée et que la base de données n'a été accessible que par l'outil SQLite Manager, sa user_version sera 0. Si le fichier de base de données a été ouvert en copiant le fichier de base de données à partir d'une application Android qui utilise une sous-classe de SQLiteOpenHelper, il aura un user_version de 1 ou plus (selon la dernière valeur utilisée comme 4ème paramètre du constructeur de SQLiteOpenHelper). Bien sûr, si la user_version est modifiée par programme, une telle modification serait également reflétée si le fichier était copié dans un outil SQlite Manager.

Avant de copier le fichier, la user_version serait généralement modifiée dans l'outil SQlite Manager en une valeur appropriée.

Vous pouvez modifier la version_utilisateur en utilisant le SQL PRAGMA user_version = 5; Vous pouvez récupérer la user_version en utilisant soit PRAGMA user_version ou SELECT * FROM pragma_user_version;

Si vous avez besoin de vérifier la version avant d'ouvrir la base de données, vous pouvez lire les 4 octets au décalage 60 et convertir les 4 octets en un entier, pour vérifier la user_version par rapport à une autre valeur. Sinon, vous devrez probablement copier le fichier, probablement en utilisant un nom différent, à partir du dossier assets, l'ouvrir en tant que SQLiteDatabase et récupérer le user_version en utilisant le SQL ci-dessus, puis le comparer à l'autre valeur, en fermant le fichier de base de données. La suppression du fichier s'il n'est pas nécessaire, sinon la suppression du fichier de base de données précédent, puis le renommage du fichier copié.

Exemple

Ce qui suit est un exemple de travail (notant que j'utilise rarement Kotlin et cela a été converti à l'aide d'AS Studio à partir de Java).

Cela utilise une classe, à savoir SQLAssetVersionCheck qui extrait le numéro de version du fichier plutôt que d'ouvrir le fichier en tant que 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
    }
}

Et voici une activité qui utilise la classe ci-dessus deux fois pour essayer de vérifier la version dans testdb fichier.

  • La première utilisation ne trouve pas le fichier de base de données testdb tel qu'il recherche dans les actifs dossier (pas le sous-répertoire des bases de données).

  • La deuxième utilisation trouve le testdb fichier comme sous-répertoire databases est spécifié (3ème paramètre du constructeur complet), se trouvant dans les assets/databases/ dossier, c'est-à-dire 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")
    }
}

Résultat (journal) :-

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
  • La première tentative ne trouve pas le fichier (l'exception qui a été interceptée est affichée) et affiche la ligne Le résultat de la vérification de version était - L'actif, pour la base de données testdb n'était pas situé dans testdb à afficher.

  • La deuxième tentative fonctionne et aboutit à Le résultat de la vérification de version était - L'actif était localisé et le numéro de version étant 5 était inférieur à la version à vérifier qui était 100

  • L'écart des lignes vides a été ajouté pour séparer la deuxième tentative de la première.

Supplémentaire

Après avoir utilisé l'outil SQLite Manager (Navicat) et utilisé :-

PRAGMA user_version = 101;

Ensuite, copiez le fichier (après avoir fermé la connexion dans Navicat) dans le dossier assets (j'ai donc deux fichiers testdb) puis le résultat est :-

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
  • c'est-à-dire le nouveau fichier a la user_version comme 101 et donc le premier trouve le fichier, le second trouve le fichier (user_version 5) comme avant.