Ложная ошибка SQLite? код 14 - PullRequest
0 голосов
/ 17 мая 2018

Я столкнулся со странной проблемой.Я запрашивал таблицу базы данных для списка слов и смог получить список.Но я не могу обновить эту таблицу.Странно то, что logcat показывает ошибку Code 14.Я удалил приложение, перезапустил его, чтобы БД была недавно скопирована, но ничего не изменилось.

Вот код dbHandler:

public VocabDatabase(Context context) {

    super(context, DB_NAME, null, 1);
    this.myContext = context;
    this.DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
}

/**
 * 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.getWritableDatabase();

        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() {
    this.getReadableDatabase();

    SQLiteDatabase checkDB = null;

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

    } catch (SQLiteException e) {
        e.printStackTrace();
    }

    if (checkDB != null) {

        checkDB.close();

    }

    return (checkDB != null) ? true : false;
}
private boolean checkDataBaseAlt(){
    File chkdb = new File(DB_PATH);
    return chkdb.exists();
}

/**
 * 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(DB_NAME);

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

    //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 = 0;
    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 + DB_NAME;
    myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);

}

@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) {
    if (newVersion > oldVersion) {
        try {
            copyDataBase();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

// 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.

//add your public methods for insert, get, delete and update data in database.

public Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) {
    SQLiteDatabase db = this.getWritableDatabase();
    return db.query(table, columns, selection, selectionArgs, groupBy, having, orderBy);
}

public long insert(String table, String nullColumnHack, ContentValues contentValues) {
    SQLiteDatabase db = this.getWritableDatabase();
    return db.insert(table, nullColumnHack, contentValues);
}

public Cursor rawQuery(String string, String[] selectionArguments) {
    SQLiteDatabase db = this.getWritableDatabase();
    return db.rawQuery(string, selectionArguments);
}
public long update(String table, ContentValues contentValues, String whereClause, String[] whereArgs) {
    SQLiteDatabase db = this.getWritableDatabase();
    return db.update(table, contentValues, whereClause, whereArgs);
}

}

А вот код услуги:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    vdb = new VocabDatabase(this);
    Toast.makeText(this, "Service started", Toast.LENGTH_SHORT).show();
    createDB();
    queryDB();
    return super.onStartCommand(intent, flags, startId);
}
private void createDB() {
    vdb.getWritableDatabase();
    try {
        vdb.createDataBase();
        vdb.openDataBase();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
public void queryDB() {
    String vet = "";
    ArrayList<String> lister = new ArrayList<>();
    Cursor cr = vdb.query(TABLE_NAME, null, null, null, null, null, null);
if (cr.moveToFirst()) {
        do {
            lister.add(cr.getString(0));
        } while (cr.moveToNext());
    }
cr.close();
String vet="";
for (String v : lister) {
            vet += v + "\t";
        }
}

String-vet отображается втост, и я вижу все слова в первом столбце таблицы.Но я не могу обновить строки.

private void updateInDatabase(String up, String pot) {
    ContentValues conval = new ContentValues();
    conval.put(pot, "1");
    try {
        long res = vdb.update(TABLE_NAME, conval, "Word=?", new String[]{up});
    } catch (Exception e) {

    }
}

Я дал разрешения на хранение и дважды проверил то же самое.

Файл манифеста:

<?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.example.hack.corrector">
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" tools:remove="android:maxSdkVersion"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INTERNET"/>
<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <service android:name=".scrapeservice"/>
</application>

Журнал ошибок:

05-17 13:39:04.614 28088-28088/com.example.hack.corrector E/SQLiteLog: (14) cannot open file at line 31282 of [5a3022e081]
05-17 13:39:04.615 28088-28088/com.example.hack.corrector E/SQLiteLog: (14) os_unix.c:31282: (21) open(/data/user/0/com.example.hack.corrector/databases/) - 
05-17 13:39:04.616 28088-28088/com.example.hack.corrector E/SQLiteDatabase: Failed to open database '/data/user/0/com.example.hack.corrector/databases/'.
    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:207)
        at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:191)
        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:806)
        at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:791)
        at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
        at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:669)
        at com.example.hakc.corrector.VocabDatabase.checkDataBase(VocabDatabase.java:81)
        at com.example.hakc.corrector.VocabDatabase.createDataBase(VocabDatabase.java:48)
        at com.example.hakc.corrector.scrapeservice.createDB(scrapeservice.java:48)
        at com.example.hakc.corrector.scrapeservice.onStartCommand(scrapeservice.java:39)
        at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3049)
        at android.app.ActivityThread.access$2300(ActivityThread.java:154)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1479)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:157)
        at android.app.ActivityThread.main(ActivityThread.java:5571)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:745)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:635)
05-17 1

Ответы [ 4 ]

0 голосов
/ 17 мая 2018

Я понял, в чем проблема. Именно в сервисе, с которого делается запрос. В методе createDB() я использовал vdb.getWritableDatabase(). Когда я это закомментировал, запрос работал гладко. Вся база данных скопирована, и запросы обрабатываются отлично. Мне нужно проверить «обновление», хотя ... Я искренне благодарю вас, ребята, что выслушали меня и нашли время, чтобы помочь мне решить эту проблему. Благодаря вашим ответам я многое узнал о том, как с базами данных обмениваются данными должным образом.

0 голосов
/ 17 мая 2018

Как говорит исключение:

Не удалось открыть базу данных '/data/user/0/com.example.hack.corrector/databases/'.

Вы пытаетесь открыть базу данных SQLite с переменной DB_PATH, установленной как

this.DB_PATH = context.getApplicationInfo().dataDir + "/databases/";

Вы не устанавливаете имя файла, только задаете путь к каталогу. databases/ - это каталог.

Установите имя файла по вашему пути:

this.DB_PATH = context.getApplicationInfo().dataDir + "/databases/my_db";

EDIT: у вас есть две переменные имени БД ... вы используете DB_NAME, чтобы открыть соединение с помощником (в конструкторе super), а затем в методе проверки, который вы использовали DB_PATH.

Таким образом, вы можете получить соединение от помощника

this.getWritableDatabase(); //Using the DB at `DB_NAME`

Но не удалось установить соединение с

String myPath = DB_PATH;
SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);

Потому что вы использовали DB_PATH здесь, а не DB_NAME. Вы используете 2 разных пути к БД.

0 голосов
/ 17 мая 2018

Полагаю, вы обнаружите, что не может открыть ошибку базы данных на самом деле не сбой, а указание на проблему.То есть ошибка открытия встречается методом checkdataBase, потому что он не может открыть базу данных, как говорится в сообщении.Это, поскольку оно перехвачено, не приводит к сбою.

Скорее всего, метод checkDatabase возвращает false, поскольку он не может открыть базу данных, и поэтому база данных копируется из ресурсов каждый разПриложение запущено.Таким образом отменяя любые изменения из предыдущего запуска.

Это просто диагностировать / отладить, используя две строки кода.

  1. , добавив Log.d("DBEXISTCHK", "Method checkdataBase returned" + String.valueOf(dbExist));

согласно: -

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

    boolean dbExist = checkDataBase();
    Log.d("DBEXISTCHK", "Method checkdataBase returned" + String.valueOf(dbExist)); //<<<<<<<<<< ADDED

    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.getWritableDatabase();
        try {
            copyDataBase();
        } catch (IOException e) {
            throw new Error("Error copying database");
        }
    }
}

и

, добавив Log.d("DBCOPY","Database is being copied from the Assets.");

согласно: -

private void copyDataBase() throws IOException {

    Log.d("DBCOPY","Database is being copied from the Assets."); //<<<<<<<<<< ADDED

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

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

    //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 = 0;
    while ((length = myInput.read(buffer)) > 0) {
        myOutput.write(buffer, 0, length);
    }

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

}

Полученный в результате журнал будет аналогичен ( обратите внимание на две последние строки ): -

05-17 10:12:22.591 1152-1152/bcdbfa.basiccopydbfromassets E/SQLiteLog: (14) cannot open file at line 30174 of [00bb9c9ce4]
    (14) os_unix.c:30174: (21) open(/data/data/bcdbfa.basiccopydbfromassets/databases/) - 
05-17 10:12:22.591 1152-1152/bcdbfa.basiccopydbfromassets E/SQLiteDatabase: Failed to open database '/data/data/bcdbfa.basiccopydbfromassets/databases/'.
    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 bcdbfa.basiccopydbfromassets.VocabDatabase.checkDataBase(VocabDatabase.java:85)
        at bcdbfa.basiccopydbfromassets.VocabDatabase.createDataBase(VocabDatabase.java:45)
        at bcdbfa.basiccopydbfromassets.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)
05-17 10:12:22.591 1152-1152/bcdbfa.basiccopydbfromassets W/System.err: 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)
05-17 10:12:22.599 1152-1152/bcdbfa.basiccopydbfromassets W/System.err:     at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
        at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:669)
        at bcdbfa.basiccopydbfromassets.VocabDatabase.checkDataBase(VocabDatabase.java:85)
        at bcdbfa.basiccopydbfromassets.VocabDatabase.createDataBase(VocabDatabase.java:45)
        at bcdbfa.basiccopydbfromassets.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)
05-17 10:12:22.599 1152-1152/bcdbfa.basiccopydbfromassets D/DBEXISTCHK: Method checkdataBase returnedfalse
05-17 10:12:22.599 1152-1152/bcdbfa.basiccopydbfromassets D/DBCOPY: Database is being copied from the Assets.

Исправление

Исправление еще проще, его просто нужно изменить: -

    String myPath = DB_PATH;

на

    String myPath = DB_PATH + DB_NAME;

в методе checkDatabase.

В этом случае результат в журнале (если регистрация оставлена) будет: -

05-17 10:30:49.809 1265-1265/? D/DBEXISTCHK: Method checkdataBase returnedtrue

Дополнительно

Комментарий

создается только пустая база данных с тем же именем.

Это потому, что вы звоните getWritableDatabase в createDBперед вызовом метода createDatabase.То есть getWritableDatabase, если базы данных нет, создаст пустую базу данных (исключая таблицу sqlite_master, а для android таблицу android_metadata), а затем вызовет метод onCreate.Это объясняет, почему, когда полный путь правильный, что копия базы данных обойдена, и что в результате пустая база данных существует в результате.

И затем комментарий

Но когдаЯ изменил «myPath» обратно на myPath = DB_Path;вся база данных была скопирована, но проблема по-прежнему сохраняется.

Если путь указан неверно, то, как описано выше, метод checkDatabase всегда будет возвращать значение false, и, таким образом, вызывается метод copyDatabase,тогда это работает, поскольку используемые пути являются правильными.

Итак,

private void createDB() {
    vdb.getWritableDatabase(); //<<<<<<<<<< The villainous line
    try {
        vdb.createDataBase();
        vdb.openDataBase();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

должно быть

private void createDB() {
    try {
        vdb.createDataBase();
        vdb.openDataBase();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Очевидно, что все пути представляют собой полный путь, который включает в себя имябаза данных.

0 голосов
/ 17 мая 2018

Эта проблема, если вы запускаете свое приложение на уровне API 23 или выше из-за новой модели разрешений в реальном времени, представленной в этом разделе. В этих версиях пользователи предоставляют разрешения приложениям во время работы приложения

Для получения разрешений во время выполнения вам нужно будет запросить пользователя. Вы можете сделать это следующим образом:

Запрос на разрешение

String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
requestPermissions(permissions, REQUEST_CODE); //REQUEST_CODE can be any Integer value

И проверьте свой Результат разрешения

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
       case REQUEST_CODE:
         if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
           //Permission granted.
           //Now you can try your database creating and writing stuff.

         }
       else{
           //Permission denied.
         }
        break;
    }
}

Если это не решит вашу проблему, перейдите по этой ссылке. Количество решений здесь для той же проблемы.

android.database.sqlite.SQLiteCantOpenDatabaseException: неизвестная ошибка (код 14): не удалось открыть базу данных

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...