如何修复未找到/已损坏的表?

时间:2018-04-24 19:54:54

标签: java android database sqlite android-sqlite

您好我正在尝试在Android Studio中创建一个简单的登录应用程序,其中从SQLite表中读取用户数据。到目前为止,我已经创建了我的表,并且从头到尾完全遵循了这个tutorial。但是我一直找不到表或表损坏错误。这是我的代码:

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 :(得分:1)

您的问题是文件 gransha.db 不是有效的数据库文件

  

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

然后发生的是,SQLiteDatabase OpenOrCreate方法(由SQLiteOpenHelper的子类调用)删除该文件并创建一个空数据库,因此为什么在获取损坏的数据库后运行时会得到未找到的表。

修复是为了确保在将数据库文件复制到assets文件夹之前使用SQLite工具(例如,针对SQLite的Db浏览器,DBeaver,SQLite Manager ....)创建和保存数据库文件,然后删除应用程序的数据(删除空的但有效的数据库)并重新运行应用程序。

实际测试你的代码时你遇到了checkUserExist方法的问题,因为它由于字符串没有用引号括起来而失败,所以值test和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;
    }
} 

这是推荐的方法(你不会让SQL注入警察跳进来)。那是你的代码吗?在字符串中,根据args中的值(代表您逃避)按顺序替换。即第一个?将被第一个arg取代,第二个?由第二个arg ..........

我还建议不要使用硬编码的DB Path: -

    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,而不是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 for SQLite3),创建了数据库,添加了表格和数据,保存了它(关闭连接),将文件复制到资源文件夹,运行App(删除App&#39后) ; s数据),它的工作原理。

因此可以使用Navicat,更多的是它是如何使用的。