net.sqlcipher.database.SQLiteException: 错误代码 14: 无法打开数据库
net.sqlcipher.database.SQLiteException: error code 14: Could not open database
我正在尝试使用 SQLCipher 创建本地 SQLite 数据库
这是我 creating/writing 到数据库的方法:
class DatabaseUtils {
val storagePath = Environment.getExternalStorageDirectory()
fun storeTransaction(context: Context, password: String, transaction: Transaction) {
SQLiteDatabase.loadLibs(context)
val databaseFile: File = context.getDatabasePath("$storagePath/Test.db")
if (!databaseFile.exists()) {
databaseFile.mkdirs()
}
val database: SQLiteDatabase = SQLiteDatabase.openOrCreateDatabase(databaseFile, password, null)
database.execSQL("CREATE TABLE IF NOT EXISTS Transactions(cardNumber INTEGER)")
database.execSQL("INSERT INTO Transactions(cardNumber) VALUES(${transaction.cardNumber})")
database.close()
}
}
我已经声明了
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
和
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
在我的清单中,当我像这样调用函数时请求权限:
override fun onStart() {
super.onStart()
initUI()
if (ContextCompat.checkSelfPermission(context!!, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity!!,
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
1)
}
if (ContextCompat.checkSelfPermission(context!!, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity!!,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
2)
}
val databaseUtils = DatabaseUtils()
databaseUtils.storeTransaction(context!!,getString(R.string.app_version), Transaction("12345678"))
}
目录已创建,但调用 openOrCreateDatabase 时仍然出现上述错误。我错过了什么?
问题 #1:SQLiteDatabase
需要一个文件,但您将其设为目录:
if (!databaseFile.exists()) {
databaseFile.mkdirs()
}
删除这三行,然后删除您设备上的目录。或者,不要将 databaseFile
传递给 SQLiteDatabase.openOrCreateDatabase()
,而是传递指向目录内文件的 File
对象。
问题 #2:您正在尝试写入外部存储,但您没有权限。 ActivityCompat.requestPermissions()
不是阻塞调用。当它returns,你还没有权限。然而,在您的代码中,您正在尝试使用您尚未拥有的权限。
除此之外:
不要对 assemble SQL 语句使用字符串连接,就像您在第二个 execSQL()
调用中一样。使用 ?
作为占位符并将您的参数作为第二个参数传递给 execSQL()
。这对于字符串尤其重要,因为 SQLCipher+SQLite 会为您正确转义特殊字符和内容。
您正在主应用程序线程上执行磁盘 I/O,这将导致您的应用 UI 在 I/O 发生时冻结。
我正在尝试使用 SQLCipher 创建本地 SQLite 数据库
这是我 creating/writing 到数据库的方法:
class DatabaseUtils {
val storagePath = Environment.getExternalStorageDirectory()
fun storeTransaction(context: Context, password: String, transaction: Transaction) {
SQLiteDatabase.loadLibs(context)
val databaseFile: File = context.getDatabasePath("$storagePath/Test.db")
if (!databaseFile.exists()) {
databaseFile.mkdirs()
}
val database: SQLiteDatabase = SQLiteDatabase.openOrCreateDatabase(databaseFile, password, null)
database.execSQL("CREATE TABLE IF NOT EXISTS Transactions(cardNumber INTEGER)")
database.execSQL("INSERT INTO Transactions(cardNumber) VALUES(${transaction.cardNumber})")
database.close()
}
}
我已经声明了
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
和
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
在我的清单中,当我像这样调用函数时请求权限:
override fun onStart() {
super.onStart()
initUI()
if (ContextCompat.checkSelfPermission(context!!, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity!!,
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
1)
}
if (ContextCompat.checkSelfPermission(context!!, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity!!,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
2)
}
val databaseUtils = DatabaseUtils()
databaseUtils.storeTransaction(context!!,getString(R.string.app_version), Transaction("12345678"))
}
目录已创建,但调用 openOrCreateDatabase 时仍然出现上述错误。我错过了什么?
问题 #1:SQLiteDatabase
需要一个文件,但您将其设为目录:
if (!databaseFile.exists()) {
databaseFile.mkdirs()
}
删除这三行,然后删除您设备上的目录。或者,不要将 databaseFile
传递给 SQLiteDatabase.openOrCreateDatabase()
,而是传递指向目录内文件的 File
对象。
问题 #2:您正在尝试写入外部存储,但您没有权限。 ActivityCompat.requestPermissions()
不是阻塞调用。当它returns,你还没有权限。然而,在您的代码中,您正在尝试使用您尚未拥有的权限。
除此之外:
不要对 assemble SQL 语句使用字符串连接,就像您在第二个
execSQL()
调用中一样。使用?
作为占位符并将您的参数作为第二个参数传递给execSQL()
。这对于字符串尤其重要,因为 SQLCipher+SQLite 会为您正确转义特殊字符和内容。您正在主应用程序线程上执行磁盘 I/O,这将导致您的应用 UI 在 I/O 发生时冻结。