SQLiteCantOpenDatabaseException:未知错误(代码 14 SQLITE_CANTOPEN):无法打开数据库
SQLiteCantOpenDatabaseException: unknown error (code 14 SQLITE_CANTOPEN): Could not open database
我正在使用以下代码打开或创建一个 sqlite 数据库。该代码在某些手机上运行良好,但在 Android P 设备上出现以下错误。
SQLiteDatabase myDB = null;
myDB = backup.this.openOrCreateDatabase(url[0], MODE_PRIVATE, null);
Logcat
2019-11-14 07:49:56.204 10213-10363/com.gadha.garden E/SQLiteLog: (14) cannot open file at line 36667 of [c255889bd9]
2019-11-14 07:49:56.204 10213-10363/com.gadha.garden E/SQLiteLog: (14) os_unix.c:36667: (2) open(/sdcard/Download/2019-11-14 07-49-56 AM.db) -
2019-11-14 07:49:56.241 10213-10363/com.gadha.garden E/SQLiteDatabase: Failed to open database '/sdcard/Download/2019-11-14 07-49-56 AM.db'.
android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14 SQLITE_CANTOPEN): Could not open database
at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:211)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:195)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:503)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:204)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:196)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:880)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:865)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:766)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:772)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:757)
at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:306)
at com.gadha.garden.backup$backupRestore.doInBackground(backup.java:120)
at com.gadha.garden.backup$backupRestore.doInBackground(backup.java:108)
at android.os.AsyncTask.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
正在考虑评论
I am trying to create a database. How can use disableWriteAheadLogging
before creating a database? –
那么我相信你的问题是你没有授予所需的权限,即使你说你有 :-
Added both read and write permissions.
您需要授予 WRITE_EXTERNAL_STORAGE(这隐含授予 READ_EXTERNAL_STORAGE)。
对于设备 API 23+ Android 6+ 而不是 9+ 这需要通过 MANIFEST 授予权限,例如:-
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
而且用户根据 Permission approval授予访问权限。对于小于 API 23 的设备,只需要清单许可。
例子
以下是一个简单的例子,boh 重现了这个问题并表明授予权限可以解决问题。
- 清单包含上述 使用权限 条目。
通过以下方式重新获得用户权限 (ExternalStoragePermissions.java) :-
abstract class ExternalStoragePermissions {
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
public ExternalStoragePermissions(Activity callingActivity) {}
// Note call this method
public static void verifyStoragePermissions(Activity activity) {
int permission = ActivityCompat.checkSelfPermission(
activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if(permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
}
使用的activity(MainActivity.java)是:-
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(Build.VERSION.SDK_INT >= 23) {
ExternalStoragePermissions.verifyStoragePermissions(this);
}
SQLiteDatabase myDB = null;
myDB = this.openOrCreateDatabase("/sdcard/Download/2019-11-14 07-49-56 AM.db", MODE_PRIVATE, null);
DatabaseUtils.dumpCursor(
myDB.query("sqlite_master",null,null,null,null,null,null)
);
myDB.close();
}
}
结果
当运行 App 第一次显示时:-
但是 当主线程继续并且访问未被授予时,日志包括:-
2019-11-15 08:35:33.439 11874-11874/a.so58855993copyfromassets D/AndroidRuntime: Shutting down VM
2019-11-15 08:35:33.440 11874-11874/a.so58855993copyfromassets E/AndroidRuntime: FATAL EXCEPTION: main
Process: a.so58855993copyfromassets, PID: 11874
java.lang.RuntimeException: Unable to start activity ComponentInfo{a.so58855993copyfromassets/a.so58855993copyfromassets.MainActivity}: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14 SQLITE_CANTOPEN): Could not open database
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14 SQLITE_CANTOPEN): Could not open database
at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:197)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:505)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:206)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:198)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:915)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:895)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:786)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:812)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:797)
at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:310)
at a.so58855993copyfromassets.MainActivity.onCreate(MainActivity.java:27)
at android.app.Activity.performCreate(Activity.java:7802)
at android.app.Activity.performCreate(Activity.java:7791)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
但是在这个阶段,应用程序仍然处于活动状态,因为请求权限的对话框仍然处于活动状态。单击 允许 导致应用程序崩溃,但随后重新启动并根据包含的日志成功创建数据库:-
2019-11-15 08:41:13.615 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@5df21a1
2019-11-15 08:41:13.616 I/System.out: 0 {
2019-11-15 08:41:13.616 I/System.out: type=table
2019-11-15 08:41:13.616 I/System.out: name=android_metadata
2019-11-15 08:41:13.616 I/System.out: tbl_name=android_metadata
2019-11-15 08:41:13.616 I/System.out: rootpage=3
2019-11-15 08:41:13.616 I/System.out: sql=CREATE TABLE android_metadata (locale TEXT)
2019-11-15 08:41:13.616 I/System.out: }
2019-11-15 08:41:13.616 I/System.out: <<<<<
- 注意以上仅为演示。在要使用的应用程序中,您显然会在尝试访问数据库之前设置权限。
- 理想情况下,您不应该对路径进行硬编码,而是使用系统值,例如Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) 为路径。
- 通常,您会通过 Context 的 getDatabasePath 方法将数据库放在应用程序的数据中,而不是将数据集放在下载文件夹中。
- 应用程序数据中标准位置的权限已授予,因此无需请求。
我正在使用以下代码打开或创建一个 sqlite 数据库。该代码在某些手机上运行良好,但在 Android P 设备上出现以下错误。
SQLiteDatabase myDB = null;
myDB = backup.this.openOrCreateDatabase(url[0], MODE_PRIVATE, null);
Logcat
2019-11-14 07:49:56.204 10213-10363/com.gadha.garden E/SQLiteLog: (14) cannot open file at line 36667 of [c255889bd9]
2019-11-14 07:49:56.204 10213-10363/com.gadha.garden E/SQLiteLog: (14) os_unix.c:36667: (2) open(/sdcard/Download/2019-11-14 07-49-56 AM.db) -
2019-11-14 07:49:56.241 10213-10363/com.gadha.garden E/SQLiteDatabase: Failed to open database '/sdcard/Download/2019-11-14 07-49-56 AM.db'.
android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14 SQLITE_CANTOPEN): Could not open database
at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:211)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:195)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:503)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:204)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:196)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:880)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:865)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:766)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:772)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:757)
at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:306)
at com.gadha.garden.backup$backupRestore.doInBackground(backup.java:120)
at com.gadha.garden.backup$backupRestore.doInBackground(backup.java:108)
at android.os.AsyncTask.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
正在考虑评论
I am trying to create a database. How can use disableWriteAheadLogging before creating a database? –
那么我相信你的问题是你没有授予所需的权限,即使你说你有 :-
Added both read and write permissions.
您需要授予 WRITE_EXTERNAL_STORAGE(这隐含授予 READ_EXTERNAL_STORAGE)。
对于设备 API 23+ Android 6+ 而不是 9+ 这需要通过 MANIFEST 授予权限,例如:-
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
而且用户根据 Permission approval授予访问权限。对于小于 API 23 的设备,只需要清单许可。
例子
以下是一个简单的例子,boh 重现了这个问题并表明授予权限可以解决问题。
- 清单包含上述 使用权限 条目。
通过以下方式重新获得用户权限 (ExternalStoragePermissions.java) :-
abstract class ExternalStoragePermissions {
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
public ExternalStoragePermissions(Activity callingActivity) {}
// Note call this method
public static void verifyStoragePermissions(Activity activity) {
int permission = ActivityCompat.checkSelfPermission(
activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
if(permission != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
activity,
PERMISSIONS_STORAGE,
REQUEST_EXTERNAL_STORAGE
);
}
}
}
使用的activity(MainActivity.java)是:-
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(Build.VERSION.SDK_INT >= 23) {
ExternalStoragePermissions.verifyStoragePermissions(this);
}
SQLiteDatabase myDB = null;
myDB = this.openOrCreateDatabase("/sdcard/Download/2019-11-14 07-49-56 AM.db", MODE_PRIVATE, null);
DatabaseUtils.dumpCursor(
myDB.query("sqlite_master",null,null,null,null,null,null)
);
myDB.close();
}
}
结果
当运行 App 第一次显示时:-
但是 当主线程继续并且访问未被授予时,日志包括:-
2019-11-15 08:35:33.439 11874-11874/a.so58855993copyfromassets D/AndroidRuntime: Shutting down VM
2019-11-15 08:35:33.440 11874-11874/a.so58855993copyfromassets E/AndroidRuntime: FATAL EXCEPTION: main
Process: a.so58855993copyfromassets, PID: 11874
java.lang.RuntimeException: Unable to start activity ComponentInfo{a.so58855993copyfromassets/a.so58855993copyfromassets.MainActivity}: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14 SQLITE_CANTOPEN): Could not open database
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14 SQLITE_CANTOPEN): Could not open database
at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:215)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:197)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:505)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:206)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:198)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:915)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:895)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:786)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:812)
at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:797)
at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:310)
at a.so58855993copyfromassets.MainActivity.onCreate(MainActivity.java:27)
at android.app.Activity.performCreate(Activity.java:7802)
at android.app.Activity.performCreate(Activity.java:7791)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
但是在这个阶段,应用程序仍然处于活动状态,因为请求权限的对话框仍然处于活动状态。单击 允许 导致应用程序崩溃,但随后重新启动并根据包含的日志成功创建数据库:-
2019-11-15 08:41:13.615 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@5df21a1 2019-11-15 08:41:13.616 I/System.out: 0 { 2019-11-15 08:41:13.616 I/System.out: type=table 2019-11-15 08:41:13.616 I/System.out: name=android_metadata 2019-11-15 08:41:13.616 I/System.out: tbl_name=android_metadata 2019-11-15 08:41:13.616 I/System.out: rootpage=3 2019-11-15 08:41:13.616 I/System.out: sql=CREATE TABLE android_metadata (locale TEXT) 2019-11-15 08:41:13.616 I/System.out: } 2019-11-15 08:41:13.616 I/System.out: <<<<<
- 注意以上仅为演示。在要使用的应用程序中,您显然会在尝试访问数据库之前设置权限。
- 理想情况下,您不应该对路径进行硬编码,而是使用系统值,例如Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) 为路径。
- 通常,您会通过 Context 的 getDatabasePath 方法将数据库放在应用程序的数据中,而不是将数据集放在下载文件夹中。
- 应用程序数据中标准位置的权限已授予,因此无需请求。