Как исправить таблицу не найден / поврежден? - PullRequest
0 голосов
/ 24 апреля 2018

Привет. В настоящее время я пытаюсь создать простое приложение для входа в Android Studio, где пользовательские данные считываются из таблицы SQLite. Пока я создал свою таблицу и следовал этому уроку точно от начала до конца. Однако я продолжаю получать таблицу не найдена или ошибка таблицы. Это мой код:

package com.example.b00694394.granshataxicompany2;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

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



private static final String DATABASE_NAME = "gransha.db";
private static final int DATABASE_VERSION = 1;
private final Context context;
SQLiteDatabase db;

private static final String DATABASE_PATH = "/data/data/com.example.b00694394.granshataxicompany2/databases/";
private final String DRIVERS_TABLE ="Drivers";


public Database(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
    this.context = context;
    createDb();
}

@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {

}

@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

}

public void createDb() {
    boolean dbExist = checkDbExist();

    if (!dbExist){
        this.getReadableDatabase();
        copyDatabase();
    }

}

private boolean checkDbExist() {
    SQLiteDatabase sqLiteDatabase = null;

    try {
        String path = DATABASE_PATH + DATABASE_NAME;
        sqLiteDatabase = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);

    } catch (Exception ex){

    }

    if (sqLiteDatabase != null) {
        sqLiteDatabase.close();
        return true;
    }

    return false;

}

private void copyDatabase() {
    try {
        InputStream inputStream = context.getAssets().open(DATABASE_NAME);

        String outFileName = DATABASE_PATH + DATABASE_NAME;

        OutputStream outputStream = new FileOutputStream(outFileName);

        byte[] b = new byte[1024];
        int lenght;

        while ((lenght = inputStream.read(b)) > 0 ){
            outputStream.write(b, 0, lenght);
        }

        outputStream.flush();
        outputStream.close();
        inputStream.close();



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

}

private SQLiteDatabase openDatabase() {
    String path = DATABASE_PATH + DATABASE_NAME;
    db = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READWRITE);
    return db;
}

public void close(){
    if(db !=null){
        db.close();
    }

}

public boolean checkUserExist (String dNum, String dPass){
    String[] columns = {"Driver_Number"};
    db = openDatabase();

    String selection = "Driver_Number = " + dNum + " and Driver_Password = "+ dPass;
    String[] selectionArgs = {dNum, dPass};
    Cursor cursor = db.query(DRIVERS_TABLE, columns, selection, selectionArgs, null, null, null);
    int count = cursor.getCount();

    cursor.close();
    close();

    if (count > 0) {
        return true;
    } else {
        return false;
    }

}

}

Это журнал ошибок времени выполнения:

E/SQLiteLog: (26) file is encrypted or is not a database
E/DefaultDatabaseErrorHandler: Corruption reported by sqlite on database: /data/data/com.example.b00694394.granshataxicompany2/databases/gransha.db
E/DefaultDatabaseErrorHandler: deleting the database file: /data/data/com.example.b00694394.granshataxicompany2/databases/gransha.db
E/SQLiteLog: (14) cannot open file at line 35803 of [605907e73a]
             (14) os_unix.c:35803: (2) open(/data/data/com.example.b00694394.granshataxicompany2/databases/gransha.db) - 
E/SQLiteDatabase: Failed to open database '/data/data/com.example.b00694394.granshataxicompany2/databases/gransha.db'.
                  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:210)
                      at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:194)
                      at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:493)
                      at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:200)
                      at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:192)
                      at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:864)
                      at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:852)
                      at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:750)
                      at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:699)
                      at com.example.b00694394.granshataxicompany2.Database.openDatabase(Database.java:100)
                      at com.example.b00694394.granshataxicompany2.Database.checkUserExist(Database.java:113)
                      at com.example.b00694394.granshataxicompany2.loginPage$1.onClick(loginPage.java:40)
                      at android.view.View.performClick(View.java:6294)
                      at android.view.View$PerformClick.run(View.java:24770)
                      at android.os.Handler.handleCallback(Handler.java:790)
                      at android.os.Handler.dispatchMessage(Handler.java:99)
                      at android.os.Looper.loop(Looper.java:164)
                      at android.app.ActivityThread.main(ActivityThread.java:6494)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.example.b00694394.granshataxicompany2, PID: 11343
                  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:210)
                      at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:194)
                      at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:493)
                      at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:200)
                      at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:192)
                      at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:864)
                      at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:852)
                      at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:750)
                      at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:699)
                      at com.example.b00694394.granshataxicompany2.Database.openDatabase(Database.java:100)
                      at com.example.b00694394.granshataxicompany2.Database.checkUserExist(Database.java:113)
                      at com.example.b00694394.granshataxicompany2.loginPage$1.onClick(loginPage.java:40)
                      at android.view.View.performClick(View.java:6294)
                      at android.view.View$PerformClick.run(View.java:24770)
                      at android.os.Handler.handleCallback(Handler.java:790)
                      at android.os.Handler.dispatchMessage(Handler.java:99)
                      at android.os.Looper.loop(Looper.java:164)
                      at android.app.ActivityThread.main(ActivityThread.java:6494)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Application terminated.

Любая помощь очень ценится. Спасибо!

1 Ответ

0 голосов
/ 24 апреля 2018

Ваша проблема в том, что файл gransha.db не является допустимым файлом базы данных согласно

E/SQLiteLog: (26) file is encrypted or is not a database

Что происходит потомзаключается в том, что метод OpenOrCreate базы данных SQLite (который вызывается подклассом SQLiteOpenHelper) удаляет файл и создает пустую базу данных, поэтому при запуске после получения поврежденной базы данных вы получаете таблицу, которая не найдена.

Исправлениечтобы убедиться, что файл базы данных создан и сохранен с использованием инструмента SQLite (например, Db Browser для SQLite, DBeaver, SQLite Manager ....) перед копированием файла базы данных в папку активов, а затем удалить данные приложения (удалитьпустая, но действительная база данных) и перезапустить приложение.

На самом деле при тестировании вашего кода у вас есть проблема с методом checkUserExist, так как он не работает из-за того, что строки не заключены в кавычки, поэтому значения проверяются и123 должны быть именами столбцов (не с тестом, не являющимся именем столбца).

Так что вместо: -

    String selection = "Driver_Number = " + dNum + " and Driver_Password = "+ dPass;

Вам необходимо использовать: -

    String selection = '"Driver_Number = "' + dNum + " and Driver_Password = '"+ dPass + "'";

Однако, поскольку вы уже правильно настроили selectionArgs, следует использовать следующее: -

public boolean checkUserExist (String dNum, String dPass){
    String[] columns = {"Driver_Number"};
    db = openDatabase();

    //String selection = "Driver_Number = " + dNum + " and Driver_Password = "+ dPass; <<<< commented out
    String selection = "Driver_Number=? AND Driver_Password=?"; //<<<< ?'s replaced by values in selectionArgs
    String[] selectionArgs = {dNum, dPass};
    Cursor cursor = db.query(DRIVERS_TABLE, columns, selection, selectionArgs, null, null, null);
    int count = cursor.getCount();

    cursor.close();
    close();

    if (count > 0) {
        return true;
    } else {
        return false;
    }
} 

Thisэто рекомендуемый способ (полиция SQL-инъекций не вмешивается).Это твой код?в строке, которая заменяется в соответствии со значениями в аргументах (экранирование от вашего имени) на последовательной основе.т.е. первый?будет заменен первый аргумент, второй?по второму аргументу ..........

Я бы также предложил не использовать жестко закодированный путь к БД в соответствии с: -

    private static final String DATABASE_PATH = "/data/data/com.example.b00694394.granshataxicompany2/databases/";

, а вместо этого заменить вышеуказанное на

    private static DATABASE_PATH;

Наряду с изменением конструктора следующим образом: -

public Database(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
    this.context = context;
    DATABASE_PATH = context.getDatabasePath(DATABASE_NAME).getParent()+File.separator;
    createDb();
}

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

Таким образом, вместо checkDBExists вот альтернативный метод, который проверяет, существует ли файл: -

private boolean altCheckDBExist() {
    File chkdb =  new File(context.getDatabasePath(DATABASE_NAME).getPath());
    return chkdb.exists();
}

Таким образом, вы бы использовали это, используя: -

public void createDb() {

    /*
    boolean dbExist = checkDbExist();

    if (!dbExist){
        this.getReadableDatabase();
        copyDatabase();
    }
    */
    if (!altCheckDBExist()) {
        this.getWritableDatabase();
        copyDatabase();
    }
}
  • Обратите внимание, старый код оставлен, но закомментирован.

Протестировано с помощью Navicat

Я скачал бесплатную пробную версию Navicat (Navicat для SQLite3), создалбазы данных, добавил таблицу и данные, сохранил ее (закрытое соединение), скопировал файл в папку активов, запустил приложение (после удаления данных приложения) и все заработало.

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

...