Код 14: Невозможно открыть базу данных - PullRequest
0 голосов
/ 13 мая 2018

Я знаю, что этот вопрос задавался раньше. Но проблема в том, что тот же код (для обработчика базы данных) работает для другого приложения, но не тот, над которым я сейчас работаю. Я даже удостоверился, что разрешения даны, проверив разрешения в настройках. Вот logcat:

05-13 15: 35: 45.693 29696-29696 / com.example.hack.corrector E / SQLiteLog: (14) не удается открыть файл в строке 31282 из [5a3022e081] (14) os_unix.c: 31282: (21) открыть (/data/user/0/com.example.hack.corrector/databases/) - 05-13 15: 35: 45.694 29696-29696 / com.example.hack.corrector E / SQLiteDatabase: Не удалось открыть базу данных '/data/user/0/com.example.hack.corrector/databases/'. android.database.sqlite.SQLiteCantOpenDatabaseException: неизвестная ошибка (код 14): не удалось открыть базу данных в android.database.sqlite.SQLiteConnection.nativeOpen (собственный метод) на android.database.sqlite.SQLiteConnection.open (SQLiteConnection.java:207) на android.database.sqlite.SQLiteConnection.open (SQLiteConnection.java:191) на android.database.sqlite.SQLiteConnectionPool.openConnectionLocked (SQLiteConnectionPool.java:463) на android.database.sqlite.SQLiteConnectionPool.open (SQLiteConnectionPool.java:185) на android.database.sqlite.SQLiteConnectionPool.open (SQLiteConnectionPool.java:177) на android.database.sqlite.SQLiteDatabase.openInner (SQLiteDatabase.java:806) на android.database.sqlite.SQLiteDatabase.open (SQLiteDatabase.java:791) в android.database.sqlite.SQLiteDatabase.openDatabase (SQLiteDatabase.java:694) в android.database.sqlite.SQLiteDatabase.openDatabase (SQLiteDatabase.java:669) в com.example.hakc.corrector.VocabDatabase.openDataBase (VocabDatabase.java:127) на com.example.hakc.corrector.scrapeservice.createDB (scrapeservice.java:31) в com.example.hakc.corrector.scrapeservice.onStartCommand (scrapeservice.java:23) на android.app.ActivityThread.handleServiceArgs (ActivityThread.java:3049) на android.app.ActivityThread.access $ 2300 (ActivityThread.java:154) на android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1479) на android.os.Handler.dispatchMessage (Handler.java:102) на android.os.Looper.loop (Looper.java:157) на android.app.ActivityThread.main (ActivityThread.java:5571) в java.lang.reflect.Method.invoke (родной метод) на com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run (ZygoteInit.java:745) на com.android.internal.os.ZygoteInit.main (ZygoteInit.java:635)

и вот код обработчика базы данных:

package com.example.hack.corrector;

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

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


public class VocabDatabase extends SQLiteOpenHelper {

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

private static String DB_NAME = "ztr.db";

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 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;
}

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

}

Я проверил файловый менеджер, и база данных была скопирована и установлена. Но все равно ошибка происходит. У меня никогда не было проблем с другим приложением, которое реализовывало тот же код обработчика базы данных (Vocabdatabase). Я потратил полтора дня, пытаясь решить эту проблему, но ничего не получается ...

1 Ответ

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

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

т.е. невозможно открыть 14 для

/data/user/0/com.example.hack.corrector/databases/

пока открытый должен пытаться открыть /data/user/0/com.example.hack.corrector/databases/ztr.db

Неиспользование полного пути приведет к двум проблемам, которые могут привести к путанице.

  1. Сообщения будут выдаваться при проверке базы данных на предмет ее существования (обратите внимание, что база данных будет копироваться каждый раз, поскольку база данных никогда не будет найдена (открыта))
  2. Сообщения также будут выдаваться при попытке открыть базу данных, последняя не удалась.

В обеих ситуациях правильное использование должно быть DB_PATH + DB_NAME, а не только DB_PATH.

Далее ваш обработчик базы данных переписан, чтобы включить в него вышеупомянутое, но также изменить проверку базы данных на проверку файла, чтобы ошибка открытия 14, которая не является ошибкой, не отображалась (при копировании базы данных). из файла активов).

  • Комментарии //<<<< ???? указывают на изменения.

: -

public class VocabDatabase extends SQLiteOpenHelper {

    //The Android's default system path of your application database.
    //private static String DB_PATH = ""; //<<<< RMVD
    private static String DB_PATH_ALT; //<<<< ADDED
    private static String DB_NAME = "ztr.db";
    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 VocabDatabase(Context context) {
        super(context, DB_NAME, null, 1);
        this.myContext = context;
        //this.DB_PATH = context.getApplicationInfo().dataDir + "/databases/"; //<<<< RMVD
        this.DB_PATH_ALT = context.getDatabasePath(DB_NAME).getPath(); //<<<< ADDED

    }

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

        //boolean dbExist = checkDataBase();  //<<<< RMVD 
        boolean dbExist = checkDataBaseAlt(); //<<<< CHANGED
        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");
            }
        }
    }
    //<<<< ADDED Alternative method checks the file rather than database
    //<<<<       as such no open error 14 messages
    /**
     * 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 checkDataBaseAlt() {
        //File chkdb = new File(myContext.getDatabasePath(DB_NAME).getPath()); //<<<< RMVD
        File chkdb = new File(DB_PATH_ALT); //<<<< ADDED
        return chkdb.exists();
    }

    /**
     * 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; //<<<< RMVD so no open error 14 uses alt method
            checkDB = SQLiteDatabase.openDatabase(
                    DB_PATH_ALT, //<<<< CHANGED
                    null, 
                    SQLiteDatabase.OPEN_READWRITE
            ); 

        } catch (SQLiteException e) {
            e.printStackTrace();
        }
        if (checkDB != null) {
            checkDB.close();
        }
        return checkDB != null; //<<<< simplified
    }

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

        // 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(DB_PATH_ALT); //<<<< CHANGED

        //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; //<<<< RMVD
        myDataBase = SQLiteDatabase.openDatabase(
                DB_PATH_ALT, //<<<< CHANGED
                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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...