android - 如何从放置在资产文件夹中的Android数据库文件中读取版本号
问题描述
我在我手动放置的包数据库下的资产文件夹中有一个 SQLite 文件(如下所示:src -> main->asset->databases->q-db(q-db 是我的 SQLite 文件)。
现在我想读取它的版本号,如果这个版本放在我自己的应用程序中,我想匹配,如果没有,那么这需要复制到我的数据库中,否则会跳过。当然,第一次它会从文件中复制,下次打开应用程序时,它会检查版本号。
我用谷歌搜索了很多,但无法获得文件的版本号,我得到的是我的 SQLite 版本号,在我的情况下我不想要它。您的支持将不胜感激。
供参考:我如下类似:
解决方案
没有单个版本号,而是版本号可以是多个值。
猜测您正在谈论Android SDK SQLiteOpenHelper 使用的 user_version 。
还有application_id,它和 user_version 一样可以用作用户变量。
您已经遇到过 SQLite_Version,因此可以打折。
还有data_version,这不太可能是版本号,因为它旨在用作数据库文件是否已被实时修改的指示。
还有 schema_version,您可能不想将其用作警告:滥用此 pragma 可能会导致数据库损坏。
用户版本
如前所述,您可能正在谈论user_version。首先要注意的是,它是可供自定义使用的用户控制变量/字段。SQlite 不使用或更改user_version,但允许更改和使用它。
此外,SQLite 管理器(例如 DB Browser、Navicat 等)不会自动更改版本号。因此,在将数据库文件复制到资产文件夹之前,您必须有意更改 user_version 以使其可用(注意,如果这样做并且您正在使用该子类,SQLiteOpenHelper
并且onUpgrade
可能onDowngrade
会调用方法)。
如果 user_version 没有特别更改并且数据库仅由 SQLite Manager 工具访问,则它的 user_version 将为 0。如果通过从使用 SQLiteOpenHelper 子类的 Android 应用程序复制数据库文件来打开数据库文件,它将具有user_version 为 1 或更多(取决于用作 SQLiteOpenHelper 构造函数的第四个参数的最后一个值)。当然,如果 user_version 以编程方式更改,那么如果将文件复制到 SQlite Manager 工具中,也会反映这种更改。
在复制文件之前,user_version 通常会在 SQlite Manager 工具中更改为适当的值。
您可以使用 SQL更改user_version您可以使用或PRAGMA user_version = 5;
检索user_versionPRAGMA user_version
SELECT * FROM pragma_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
}
}
这是一个使用上述类两次尝试检查testdb文件中的版本的 Activity。
第一种用法没有找到数据库文件testdb,因为它在assets文件夹(而不是数据库子目录)中查找。
第二种用法找到testdb文件,因为指定了子目录数据库(完整构造函数的第三个参数),在assets/databases/文件夹中找到,即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")
}
}
结果(日志):-
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
添加了空白行的间隙以将第二次尝试与第一次分开。
额外的
使用 SQLite 管理器工具 (Navicat) 并使用:-
PRAGMA user_version = 101;
然后将文件(在 Navicat 中关闭连接后)复制到 assets 文件夹(所以我有两个 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),就像以前一样。
推荐阅读
- python - pip install 即使使用 --no-cache-dir 也会产生哈希不匹配
- swift - 如何使用多个条件对数组进行排序,包括枚举值、名称和数字?
- php - 如何从 MySql 表中获取所有父母和祖先?
- javascript - Vuex动作中的顺序依赖函数
- apache-spark - java.io.IOException:在 Pyspark 中写入大文件时流损坏
- reactjs - 更改检测事件更改了 Ag Grid 单元格值
- c# - 它是安全的 serilog 配置作为 XML 配置而不是 .netframework 中的 c#
- multithreading - 我应该为可重新启动的多线程弹簧批处理使用哪个阅读器、编写器、处理器?
- python - Python:如何使用线性回归预测 NAN 值?
- postgresql - AWS Postgres 复制错误“pg-wal-archive 尚未下载”