【问题标题】:Specified directory or database file does not exist指定的目录或数据库文件不存在
【发布时间】:2018-08-28 09:01:00
【问题描述】:

多年来,我一直在从事我的 android 项目,我一直使用此代码作为数据库处理程序来设置 sqlite 数据库,但这些天我在新笔记本电脑上安装了 android studio 并开始运行我的项目,但我收到此错误消息一次应用启动:

08-26 13:41:51.044 16032-16032/com.nileworx.flagsquiz E/SQLiteLog: (28) failed to open "/data/data/com.nileworx.flagsquiz/databases/FlagsQuiz" with flag (131072) and mode_t (0) due to error (2)
    (14) cannot open file at line 32561 of [a66a5b397b]
    (14) os_unix.c:32561: (2) open(/data/data/com.nileworx.flagsquiz/databases/FlagsQuiz) - 
08-26 13:41:51.054 16032-16032/com.nileworx.flagsquiz E/SQLiteDatabase: Failed to open database '/data/data/com.nileworx.flagsquiz/databases/FlagsQuiz'.
    android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 1294): Could not open database
    #################################################################
    Error Code : 1294 (SQLITE_CANTOPEN_ENOENT)
    Caused By : Specified directory or database file does not exist.
        (unknown error (code 1294): Could not open database)
    #################################################################
        at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:301)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:220)
        at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:512)
        at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:206)
        at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:178)
        at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:908)
        at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:878)
        at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:699)
        at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:674)
        at com.nileworx.flagsquiz.DataBaseHandler.checkDataBase(DataBaseHandler.java:86)
        at com.nileworx.flagsquiz.DataBaseHandler.createDataBase(DataBaseHandler.java:47)
        at com.nileworx.flagsquiz.DAO.<init>(DAO.java:52)
        at com.nileworx.flagsquiz.CustomDialog.<init>(CustomDialog.java:46)
        at com.nileworx.flagsquiz.MainActivity.onCreate(MainActivity.java:73)
        at android.app.Activity.performCreate(Activity.java:6609)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1134)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3113)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3275)
        at android.app.ActivityThread.access$1000(ActivityThread.java:218)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1744)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:145)
        at android.app.ActivityThread.main(ActivityThread.java:7007)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)

这是我的 DatabaseHandler.java :

package com.nileworx.flagsquiz;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;

public class DataBaseHandler extends SQLiteOpenHelper {

    // The Android's default system path of your application database.
    private static String DB_PATH;

    private static String DB_NAME = "FlagsQuiz";

    private SQLiteDatabase myDataBase;

    private final Context myContext;

    /**
     * Constructor Takes and keeps a reference of the passed context in order to
     * access to the application assets and resources.
     * 
     * @param context
     */
    public DataBaseHandler(Context context) {

        super(context, DB_NAME, null, 1);
        this.myContext = context;
        DB_PATH = context.getDatabasePath(DB_NAME).toString();
//      Log.e("path", DB_PATH);
    }

    // ==============================================================================

    /**
     * Creates a empty database on the system and rewrites it with your own
     * database.
     * */
    public void createDataBase() throws IOException {

        boolean dbExist = checkDataBase();

        if (dbExist) {
            // do nothing - database already exist
        } else {

            // By calling this method and empty database will be created into
            // the default system path
            // of your application so we are gonna be able to overwrite that
            // database with our database.
            this.getReadableDatabase();

            try {

                copyDataBase();

            } catch (IOException e) {

                throw new Error("Error copying database");

            }
        }

    }

    // ==============================================================================

    /**
     * Check if the database already exist to avoid re-copying the file each
     * time you open the application.
     * 
     * @return true if it exists, false if it doesn't
     */
    private boolean checkDataBase() {

        SQLiteDatabase checkDB = null;

        try {
            String myPath = DB_PATH;
            checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

        } catch (SQLiteException e) {

            // database does't exist yet.

        }

        if (checkDB != null) {

            checkDB.close();

        }

        return checkDB != null ? true : false;
    }

    // ==============================================================================

    /**
     * Copies your database from your local assets-folder to the just created
     * empty database in the system folder, from where it can be accessed and
     * handled. This is done by transfering bytestream.
     * */
    private void copyDataBase() throws IOException {

        // Open your local db as the input stream
        InputStream myInput = myContext.getAssets().open("database/" + DB_NAME);

        // Path to the just created empty db
        String outFileName = DB_PATH;

        // Open the empty db as the output stream
        OutputStream myOutput = new FileOutputStream(outFileName);

        // transfer bytes from the inputfile to the outputfile
        byte[] buffer = new byte[1024];
        int length;
        while ((length = myInput.read(buffer)) > 0) {
            myOutput.write(buffer, 0, length);
        }

        // Close the streams
        myOutput.flush();
        myOutput.close();
        myInput.close();

    }

    // ==============================================================================

    public void openDataBase() throws SQLException {

        // Open the database
        String myPath = DB_PATH;
        myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

    }

    // ==============================================================================

    @Override
    public synchronized void close() {

        if (myDataBase != null)
            myDataBase.close();

        super.close();

    }

    // ==============================================================================

    @Override
    public void onCreate(SQLiteDatabase db) {

    }

    // ==============================================================================

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    // Add your public helper methods to access and get content from the
    // database.
    // You could return cursors by doing "return myDataBase.query(....)" so it'd
    // be easy
    // to you to create adapters for your views.

}

这是我的数据库文件目录结构:

清单文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.nileworx.flagsquiz"
    android:versionCode="7"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="18" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/app_icon"
        android:label="@string/app_name"
        tools:replace="android:label"
        android:largeHeap="true"
        android:theme="@style/AppTheme" >
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
        <meta-data
            android:name="com.google.android.gms.games.APP_ID"
            android:value="@string/app_id" />

        <activity
            android:name="com.nileworx.flagsquiz.MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.nileworx.flagsquiz.UpdatesDialogActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:theme="@android:style/Theme.Dialog" >
        </activity>
        <activity
            android:name="com.nileworx.flagsquiz.GameActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait" >
        </activity>
        <activity
            android:name="com.nileworx.flagsquiz.SettingsActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait" >
        </activity>
        <activity
            android:name="com.google.android.gms.ads.AdActivity"
            android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" />

        <service android:name="com.nileworx.flagsquiz.GetUpdatesService" >
        </service>
        <service android:name="com.nileworx.flagsquiz.CheckUpdatesService" >
        </service>
    </application>

</manifest>

DAO.java

public DAO(Context context) {
        dbHandler = new DataBaseHandler(context);
        try {

            dbHandler.createDataBase();

        } catch (IOException ioe) {

            throw new Error("Unable to create database");

        }
        try {

            dbHandler.openDataBase();

        } catch (SQLException sqle) {

            throw sqle;

        }
        // Log.e("path2",
        // context.getDatabasePath("FootballFlagQuiz").toString());
    }

现在我该如何解决这个问题? 提前致谢!

【问题讨论】:

  • 你能在这里添加你的清单文件吗?
  • 你听说过google room吗?如果您对更简单的 sqlite 方法持开放态度,可以尝试一下
  • @LokeshDesai 我添加了它.. 检查编辑
  • 您是否处理过写入外部存储的运行时权限?
  • @Dr.aNdRO 其实我之前没听说过..我想先知道为什么会出现这个错误??是关于新的 android api 级别还是什么?因为我总是使用这种方法

标签: android database sqlite


【解决方案1】:

根据您的代码,这是预期的。它在checkDatabase中打开异常。它说数据库文件还不存在。如果这是一个新安装,那将是真的。您甚至在编写代码以期待这一点——看到您的 catch 语句了吗?这就是你如何判断数据库是否是新的。

这里没有错。这将在任何设备上首次打印出来,并且仍然可以工作。如果您想删除该消息,请从您的 catch 语句中取出日志记录。

【讨论】:

  • 但我试图再次打开它很多次,应用程序仍然崩溃并强制关闭
  • 那你在别处发生了崩溃。这不会让你崩溃。
【解决方案2】:

您的代码似乎没问题。

我已经复制了您提供的所有代码并尝试重新创建您遇到的错误。

首先,您显示的堆栈跟踪是意料之中的,因为这是您使用(在 checkDB 方法中)时不可避免的被捕获(通过 catch 捕获)的结果:-

checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

然后数据库不存在。堆栈跟踪不是来自致命异常。但是,堆栈跟踪本身是在 openDatabase 方法中发出的,因此不容易被抑制。

因此,任何 FATAL EXCEPTION 都必须在其他地方。您应该进一步检查日志。

在没有正确命名的文件(例如 FlagsQuiz.txt 而不是 FlagsQuiz)的情况下运行您的代码会导致(注意日志已添加到您的代码中)

即用于测试的两个文件(扩展名 NOTADB 不是 sqlite 数据库,扩展名 txt 是添加了扩展名的有效 sqlite 数据库):-

结果:-

08-29 01:01:19.323 2602-2602/? D/CHKDB: Issuing openDatabase for path :- /data/data/so52053932.so52053932/databases/FlagsQuiz
08-29 01:01:19.331 2602-2602/? E/SQLiteLog: (14) cannot open file at line 30174 of [00bb9c9ce4]
    (14) os_unix.c:30174: (2) open(/data/data/so52053932.so52053932/databases/FlagsQuiz) - 
08-29 01:01:19.331 2602-2602/? E/SQLiteDatabase: Failed to open database '/data/data/so52053932.so52053932/databases/FlagsQuiz'.
    android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
        at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
        at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
        at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
        at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
        at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:804)
        at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:789)
        at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
        at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:669)
        at so52053932.so52053932.DataBaseHandler.checkDataBase(DataBaseHandler.java:89)
        at so52053932.so52053932.DataBaseHandler.createDataBase(DataBaseHandler.java:48)
        at so52053932.so52053932.DAO.<init>(DAO.java:17)
        at so52053932.so52053932.MainActivity.onCreate(MainActivity.java:18)
        at android.app.Activity.performCreate(Activity.java:5008)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
        at android.app.ActivityThread.access$600(ActivityThread.java:130)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:4745)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
        at dalvik.system.NativeStart.main(Native Method)
08-29 01:01:19.331 2602-2602/? D/CHECKDB: SQLiteException has bee caught.
08-29 01:01:19.339 2602-2602/? D/ONCREATE: New Database has been created so ONCREATE has been invoked.
08-29 01:01:19.339 2602-2602/? D/CPYDB: Database Copy Initiated. Trying to open InputStream i.e. asset database/FlagsQuiz
08-29 01:01:19.339 2602-2602/? W/System.err: java.io.FileNotFoundException: database/FlagsQuiz
        at android.content.res.AssetManager.openAsset(Native Method)
        at android.content.res.AssetManager.open(AssetManager.java:315)
        at android.content.res.AssetManager.open(AssetManager.java:289)
        at so52053932.so52053932.DataBaseHandler.copyDataBase(DataBaseHandler.java:119)
        at so52053932.so52053932.DataBaseHandler.createDataBase(DataBaseHandler.java:62)
        at so52053932.so52053932.DAO.<init>(DAO.java:17)
        at so52053932.so52053932.MainActivity.onCreate(MainActivity.java:18)
        at android.app.Activity.performCreate(Activity.java:5008)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
        at android.app.ActivityThread.access$600(ActivityThread.java:130)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:4745)
08-29 01:01:19.347 2602-2602/? W/System.err:     at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
        at dalvik.system.NativeStart.main(Native Method)
08-29 01:01:19.347 2602-2602/? D/AndroidRuntime: Shutting down VM
08-29 01:01:19.347 2602-2602/? W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0xa62a0288)
08-29 01:01:19.347 2602-2602/? E/AndroidRuntime: FATAL EXCEPTION: main
    java.lang.Error: Error copying database
        at so52053932.so52053932.DataBaseHandler.createDataBase(DataBaseHandler.java:67)
        at so52053932.so52053932.DAO.<init>(DAO.java:17)
        at so52053932.so52053932.MainActivity.onCreate(MainActivity.java:18)
        at android.app.Activity.performCreate(Activity.java:5008)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
        at android.app.ActivityThread.access$600(ActivityThread.java:130)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:4745)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
        at dalvik.system.NativeStart.main(Native Method)
  • 有 3 个异常(中间,显示为第 2 个的异常是在捕获/捕获最终异常时打印堆栈跟踪)。
  • 第一个异常不是 FATAL 异常,如上所述(即来自 checkDB 方法的预期异常)
  • 第二个异常是导致问题的实际异常。但是,它已被捕获(并且由于已打印了额外的代码,因此它不会出现在您的代码中,因为它没有打印出来)这是由于在这种情况下找不到资产文件(即代码是期望 FlagsQuiz 不是 FlagsQuiz.txt 也不是 FlagsQuixk.NOTADB)。
  • 第三个异常是由throw new Error("Error copying database"); createDatabase 方法中发出的。 (在您的代码中没有那么有用,代码中的真正原因/位置是隐藏的)。

注意在这个阶段,底层数据库实际上已经创建好了。**

根据08-29 01:01:19.339 2602-2602/? D/ONCREATE: New Database has been created so ONCREATE has been invoked.

例如设备资源管理器显示:-

因此,后续运行不会尝试从存在的资产中复制数据库。 但是,存在的数据库除了 sqlite_masterandroid_metadata 之外没有任何表。从应用程序的角度来看,这实际上是数据库是空的(您希望至少 16k(如果我没记错的话)作为任何其他表的另一个 4k 页)。

因此,您的真正问题是另一个问题。我建议也许修改您的代码以包括根据(见 // cmets )的临时调试:-

DAO.java

public class DAO {

    DataBaseHandler dbHandler;

    public DAO(Context context) {
        dbHandler = new DataBaseHandler(context);
        try {

            dbHandler.createDataBase();

        } catch (IOException ioe) {

            throw new Error("Unable to create database");

        }
        try {

            dbHandler.openDataBase();
            Log.d("DAO","Attempting to open the database."); //<<<<< ADDED

        } catch (SQLException sqle) {
            Log.d("DAOCONSTRUCTOR","Error attempting to Open Database."); //<<<<< ADDED
            sqle.printStackTrace(); //<<<<< ADDED
            throw sqle;
        }
        // Log.e("path2",
        // context.getDatabasePath("FootballFlagQuiz").toString());
    }
}

DataBaseHandler.java

public class DataBaseHandler extends SQLiteOpenHelper {

    // The Androids default system path of your application database.
    private static String DB_PATH;

    private static String DB_NAME = "FlagsQuiz";

    private SQLiteDatabase myDataBase;

    private final Context myContext;

    /**
     * Constructor Takes and keeps a reference of the passed context in order to
     * access to the application assets and resources.
     *
     * @param context
     */
    public DataBaseHandler(Context context) {

        super(context, DB_NAME, null, 1);
        this.myContext = context;
        DB_PATH = context.getDatabasePath(DB_NAME).toString();
//      Log.e("path", DB_PATH);
    }

    // ==============================================================================

    /**
     * Creates a empty database on the system and rewrites it with your own
     * database.
     * */
    public void createDataBase() throws IOException {

        boolean dbExist = checkDataBase();

        if (dbExist) {
            // do nothing - database already exist
        } else {

            // By calling this method and empty database will be created into
            // the default system path
            // of your application so we are gonna be able to overwrite that
            // database with our database.
            this.getReadableDatabase();

            try {

                copyDataBase();

            } catch (IOException e) {
                e.printStackTrace(); //<<<<< ADDED

                throw new Error("Error copying database");

            }
        }

    }

    // ==============================================================================

    /**
     * Check if the database already exist to avoid re-copying the file each
     * time you open the application.
     *
     * @return true if it exists, false if it doesn't
     */
    private boolean checkDataBase() {

        SQLiteDatabase checkDB = null;

        try {
            String myPath = DB_PATH;
            Log.d("CHKDB","Issuing openDatabase for path :- " + myPath); //<<<<< ADDED
            checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
            boolean checkresult = checkDB != null; //<<<<< ADDED
            Log.d("CHKDB", "Result of check is " + String.valueOf(checkresult)); //<<<<< ADDED

        } catch (SQLiteException e) {
            Log.d("CHECKDB", "SQLiteException has bee caught."); //<<<<< ADDED

            // database does't exist yet.

        }

        if (checkDB != null) {
            Log.d("CHECKDB","DB exists so closing the opened DB."); //<<<<< ADDED
            checkDB.close();
        }
        return checkDB != null ? true : false;
    }

    // ==============================================================================

    /**
     * Copies your database from your local assets-folder to the just created
     * empty database in the system folder, from where it can be accessed and
     * handled. This is done by transfering bytestream.
     * */
    private void copyDataBase() throws IOException {

        Log.d("CPYDB","Database Copy Initiated. Trying to open InputStream i.e. asset " + "database/" + DB_NAME); //<<<<< ADDED

        // Open your local db as the input stream
        InputStream myInput = myContext.getAssets().open("database/" + DB_NAME);
        Log.d("CPYDB","InputStream Opened successfully. Now trying to open OutputStream path = " + DB_PATH); //<<<<< ADDED

        // Path to the just created empty db
        String outFileName = DB_PATH;

        // Open the empty db as the output stream
        OutputStream myOutput = new FileOutputStream(outFileName);
        Log.d("CPYDB","OutputStream Opened successfully. Now trying to copy from InputStream to OutputStream."); //<<<<< ADDED

        // transfer bytes from the inputfile to the outputfile
        byte[] buffer = new byte[1024];
        int length;
        while ((length = myInput.read(buffer)) > 0) {
            myOutput.write(buffer, 0, length);
            Log.d("CPYDB","Copied " + String.valueOf(length) + " bytes."); //<<<<< ADDED
        }
        Log.d("CPYDB","Completed Copy from asset to DB. Flusing and closing Streams"); //<<<<< ADDED

        // Close the streams
        myOutput.flush();
        myOutput.close();
        myInput.close();
        Log.d("CPYDB","Copy complete and all sterams flushed and closed. Copied " + String.valueOf(length) + "bytes."); //<<<<< ADDED
    }

    // ==============================================================================

    public void openDataBase() throws SQLException {

        // Open the database
        String myPath = DB_PATH;
        myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);

    }

    // ==============================================================================

    @Override
    public synchronized void close() {

        if (myDataBase != null)
            myDataBase.close();

        super.close();

    }

    // ==============================================================================

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.d("ONCREATE","New Database has been created so ONCREATE has been invoked."); //<<<<< ADDED

    }

    // ==============================================================================

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    // Add your public helper methods to access and get content from the
    // database.
    // You could return cursors by doing "return myDataBase.query(....)" so it'd
    // be easy
    // to you to create adapters for your views.

}

通过上述更改以及对堆栈跟踪的更好理解,您将能够查明您遇到的真正错误。


有效运行

使用资产文件中的有效数据库运行您的代码,并将以下内容用作(调用)MainActivity:-

public class MainActivity extends AppCompatActivity {

    DAO myDAO;
    DataBaseHandler myDBhandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myDAO = new DAO(this);
        myDBhandler = myDAO.dbHandler;
        SQLiteDatabase db = myDBhandler.getWritableDatabase();
        Cursor csr = db.query("sqlite_master",null,null,null,null,null,null);
        while (csr.moveToNext()) {
            Log.d("COMPONENTS","Found " + csr.getString(csr.getColumnIndex("name")) + " Type is " + csr.getString(csr.getColumnIndex("type")));
        }
        csr.close();
    }
}

结果:-

08-29 01:14:06.139 2699-2699/? D/CHKDB: Issuing openDatabase for path :- /data/data/so52053932.so52053932/databases/FlagsQuiz
08-29 01:14:06.139 2699-2699/? E/SQLiteLog: (14) cannot open file at line 30174 of [00bb9c9ce4]
    (14) os_unix.c:30174: (2) open(/data/data/so52053932.so52053932/databases/FlagsQuiz) - 
08-29 01:14:06.139 2699-2699/? E/SQLiteDatabase: Failed to open database '/data/data/so52053932.so52053932/databases/FlagsQuiz'.
    android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
        at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
        at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
        at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
        at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
        at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:804)
        at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:789)
        at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
        at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:669)
        at so52053932.so52053932.DataBaseHandler.checkDataBase(DataBaseHandler.java:89)
        at so52053932.so52053932.DataBaseHandler.createDataBase(DataBaseHandler.java:48)
        at so52053932.so52053932.DAO.<init>(DAO.java:17)
        at so52053932.so52053932.MainActivity.onCreate(MainActivity.java:18)
        at android.app.Activity.performCreate(Activity.java:5008)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
        at android.app.ActivityThread.access$600(ActivityThread.java:130)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:4745)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
        at dalvik.system.NativeStart.main(Native Method)
08-29 01:14:06.139 2699-2699/? D/CHECKDB: SQLiteException has bee caught.
08-29 01:14:06.151 2699-2699/? D/ONCREATE: New Database has been created so ONCREATE has been invoked.
08-29 01:14:06.151 2699-2699/? D/CPYDB: Database Copy Initiated. Trying to open InputStream i.e. asset database/FlagsQuiz
    InputStream Opened successfully. Now trying to open OutputStream path = /data/data/so52053932.so52053932/databases/FlagsQuiz
    OutputStream Opened successfully. Now trying to copy from InputStream to OutputStream.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Copied 1024 bytes.
    Completed Copy from asset to DB. Flusing and closing Streams
    Copy complete and all sterams flushed and closed. Copied -1bytes.
08-29 01:14:06.151 2699-2699/? D/DAO: Attempting to open the database.
08-29 01:14:06.159 2699-2699/? D/COMPONENTS: Found android_metadata Type is table
    Found PrivateList Type is table
    Found PrivateProduct Type is table
    Found List_Product Type is table
    Found sqlite_autoindex_List_Product_1 Type is index

备用数据库检查

以下代码是一种替代方法,用于检查 DB 是否存在(假定为有效 DB)而不发出 SQLiteException。即它检查数据库文件而不是数据库(如果复制失败,它也不会创建一个空数据库):-

private boolean ifDatabaseExists(String dbpath) {
    File db = new File(dbpath);
    if(db.exists()) return true;
    File dir = new File(db.getParent());
    if (!dir.exists()) {
        dir.mkdirs();
    }
    return false;
}
  • 这可以用作checkDB 方法的替代方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-16
    • 1970-01-01
    • 2021-01-28
    • 2011-04-26
    • 1970-01-01
    • 2018-08-12
    • 2020-06-17
    • 1970-01-01
    相关资源
    最近更新 更多