нет такой ошибки таблицы в Android пирог после копирования базы данных из папки активов - PullRequest
0 голосов
/ 19 декабря 2018

Я не могу получить доступ к базе данных на Android пирог после копирования базы данных из папки активов.это работает на всех других версиях.Я получаю сообщение об ошибке «Нет такого столбца при выполнении операций с базой данных».Пожалуйста, помогите мне решить это.Ниже приведен класс dbhelper, который я использую:

public class DBHelper extends SQLiteOpenHelper {

    private static String DB_PATH = "/data/data/com.abc.xyz/databases/";    
    private static String DB_NAME = "db";    
    private SQLiteDatabase myDataBase;    
    private final Context myContext;

    public DBHelper(Context context) {    
        super(context, DB_NAME, null, 1);
        this.myContext = context;
    }

    /**
     * Creates an 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 + DB_NAME;
            checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
            checkDB.close();
        } 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(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;
        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_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) {
    }
}

Ответы [ 3 ]

0 голосов
/ 14 февраля 2019

Все, что мне нужно было сделать, это закрыть соединение с БД после this.getReadableDatabase () in createDataBase () :

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();
        this.close()
        try {
            copyDataBase();
        } catch (IOException e) {
            throw new Error("Error copying database");
        }
    }   
}
0 голосов
/ 01 марта 2019

Я боролся с этим уже несколько дней.Только что решил эту проблему, удалив следующую строку кода из метода createDatabase ():

this.getReadableDataBase();

Кажется, теперь работает нормально с API 27 и 28.

0 голосов
/ 20 декабря 2018

Я полагаю, что следующее решит проблемы открытия базы данных при проверке ее существования, вместо этого она проверяет, существует ли база данных в виде файла (см. Комментарии): -

public class DBHelper extends SQLiteOpenHelper {

    //private static String DB_PATH = "/data/data/com.abc.xyz/databases/"; //<<<<<<<<<< overwritten
    private static String DB_NAME = "db";
    private SQLiteDatabase myDataBase;
    private final Context myContext;

    private int bytes_copied = 0;
    private static int buffer_size = 1024;
    private int blocks_copied = 0;
    private boolean database_copied = false;
    private boolean database_existed = false;

    public DBHelper(Context context) {
        super(context, DB_NAME, null, 1);

        this.myContext = context;
        // Check for and create (copy DB from assets) when constructing the DBHelper
        if (!checkDataBase()) {
            bytes_copied = 0;
            blocks_copied = 0;
            createDataBase();
        } else {
            database_existed = true;
        }
    }

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

        boolean dbExist = checkDataBase(); // Double check
        if(dbExist){
            //do nothing - database already exist
        } else {
            //By calling this method an 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) {
                File db = new File(myContext.getDatabasePath(DB_NAME).getPath());
                if (db.exists()) {
                    db.delete();
                }
                e.printStackTrace();
                throw new RuntimeException("Error copying database (see stack-trace above)");
            }
        }
    }

    /**
     * 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() {
        /**
         * Does not open the database instead checks to see if the file exists
         * also creates the databases directory if it does not exists
         * (the real reason why the database is opened, which appears to result in issues)
         */

        File db = new File(myContext.getDatabasePath(DB_NAME).getPath()); //Get the file name of the database
        if (db.exists()) return true; // If it exists then return doing nothing

        // Get the parent (directory in which the database file would be)
        File dbdir = db.getParentFile();
        // If the directory does not exits then make the directory (and higher level directories)
        if (!dbdir.exists()) {
            dbdir.mkdirs();
        }
        return 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 {

        final String TAG = "COPYDATABASE";

        //Open your local db as the input stream
        Log.d(TAG,"Initiated Copy of the database file " + DB_NAME + " from the assets folder.");
        InputStream myInput = myContext.getAssets().open(DB_NAME); // Open the Asset file
        String dbpath = myContext.getDatabasePath(DB_NAME).getPath();
        Log.d(TAG,"Asset file " + DB_NAME + " found so attmepting to copy to " + dbpath);

        // 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(dbpath);
        //transfer bytes from the inputfile to the outputfile
        byte[] buffer = new byte[buffer_size];
        int length;
        while ((length = myInput.read(buffer))>0) {
            blocks_copied++;
            Log.d(TAG,"Ateempting copy of block " + String.valueOf(blocks_copied) + " which has " + String.valueOf(length) + " bytes.");
            myOutput.write(buffer, 0, length);
            bytes_copied += length;
        }
        Log.d(TAG,
                "Finished copying Database " + DB_NAME +
                        " from the assets folder, to  " + dbpath +
                        String.valueOf(bytes_copied) + "were copied, in " +
                        String.valueOf(blocks_copied) + " blocks of size " +
                        String.valueOf(buffer_size) + "."
        );
        //Close the streams
        myOutput.flush();
        myOutput.close();
        myInput.close();
        Log.d(TAG,"All Streams have been flushed and closed.");
    }

    public void openDataBase() throws SQLException {
        //Open the database
        //String myPath = DB_PATH + DB_NAME;
        String myPath = myContext.getDatabasePath(DB_NAME).getPath();
        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) {
    }


    @Override
    public void onConfigure(SQLiteDatabase db) {
        super.onConfigure(db);
        Log.d("DBCONFIGURE","Database has been configured ");
    }

    @Override
    public void onOpen(SQLiteDatabase db) {
        super.onOpen(db);
        Log.d("DBOPENED","Database has been opened.");
    }
}

Тестирование

Следующее действие использовалось для тестирования вышеупомянутого (примечание Создание экземпляра объекта DBHelper myDBHlpr инициирует проверку / копирование базы данных): -

public class MainActivity extends AppCompatActivity {

    DBHelper myDBhlpr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d("VERSION","Build Version is " + String.valueOf(Build.VERSION.SDK_INT));
        myDBhlpr = new DBHelper(this);
        Cursor csr = myDBhlpr.getWritableDatabase().query(
                "sqlite_master",
                null,null,null,null,null,null
        );
        while (csr.moveToNext()) {
            Log.d(
                    "DBITEMS",
                    "Found " + csr.getString(csr.getColumnIndex("name")) +
                            " which has a type of " + csr.getString(csr.getColumnIndex("type")) +
                            " the SQL used to create it, was :-\n\t" + csr.getString(csr.getColumnIndex("sql"))
            );
        }
        csr.close();
    }
}

Этап 1 -Запустите без файла базы данных (дБ) в папке ресурсов: -

  • ПРИМЕЧАНИЕ: строка в журнале /VERSION: Build Version is 28 т.е. Android Pie

Возникает исключение, которое включает трассировку стека, которая указывает на ошибку с InputStream myInput = myContext.getAssets().open(DB_NAME); (т. Е. Актив не существует, как и ожидалось.) : -

2019-01-25 17:51:12.303 30371-30371/so.cdfa D/VERSION: Build Version is 28
2019-01-25 17:51:12.304 30371-30371/so.cdfa D/COPYDATABASE: Initiated Copy of the database file db from the assets folder.
2019-01-25 17:51:12.304 30371-30371/so.cdfa W/System.err: java.io.FileNotFoundException: db
2019-01-25 17:51:12.305 30371-30371/so.cdfa W/System.err:     at android.content.res.AssetManager.nativeOpenAsset(Native Method)
2019-01-25 17:51:12.305 30371-30371/so.cdfa W/System.err:     at android.content.res.AssetManager.open(AssetManager.java:744)
2019-01-25 17:51:12.305 30371-30371/so.cdfa W/System.err:     at android.content.res.AssetManager.open(AssetManager.java:721)
2019-01-25 17:51:12.305 30371-30371/so.cdfa W/System.err:     at so.cdfa.DBHelper.copyDataBase(DBHelper.java:101)
2019-01-25 17:51:12.305 30371-30371/so.cdfa W/System.err:     at so.cdfa.DBHelper.createDataBase(DBHelper.java:55)
2019-01-25 17:51:12.305 30371-30371/so.cdfa W/System.err:     at so.cdfa.DBHelper.<init>(DBHelper.java:36)
2019-01-25 17:51:12.305 30371-30371/so.cdfa W/System.err:     at so.cdfa.MainActivity.onCreate(MainActivity.java:18)
2019-01-25 17:51:12.305 30371-30371/so.cdfa W/System.err:     at android.app.Activity.performCreate(Activity.java:7136)
2019-01-25 17:51:12.305 30371-30371/so.cdfa W/System.err:     at android.app.Activity.performCreate(Activity.java:7127)
2019-01-25 17:51:12.305 30371-30371/so.cdfa W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
2019-01-25 17:51:12.305 30371-30371/so.cdfa W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
2019-01-25 17:51:12.306 30371-30371/so.cdfa W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
2019-01-25 17:51:12.306 30371-30371/so.cdfa W/System.err:     at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
2019-01-25 17:51:12.306 30371-30371/so.cdfa W/System.err:     at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
2019-01-25 17:51:12.306 30371-30371/so.cdfa W/System.err:     at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
2019-01-25 17:51:12.306 30371-30371/so.cdfa W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
2019-01-25 17:51:12.306 30371-30371/so.cdfa W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:106)
2019-01-25 17:51:12.306 30371-30371/so.cdfa W/System.err:     at android.os.Looper.loop(Looper.java:193)
2019-01-25 17:51:12.307 30371-30371/so.cdfa W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6669)
2019-01-25 17:51:12.307 30371-30371/so.cdfa W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
2019-01-25 17:51:12.307 30371-30371/so.cdfa W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
2019-01-25 17:51:12.307 30371-30371/so.cdfa W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2019-01-25 17:51:12.307 30371-30371/so.cdfa D/AndroidRuntime: Shutting down VM
2019-01-25 17:51:12.312 30371-30371/so.cdfa E/AndroidRuntime: FATAL EXCEPTION: main
    Process: so.cdfa, PID: 30371
    java.lang.RuntimeException: Unable to start activity ComponentInfo{so.cdfa/so.cdfa.MainActivity}: java.lang.RuntimeException: Error copying database (see stack-trace above)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
     Caused by: java.lang.RuntimeException: Error copying database (see stack-trace above)
        at so.cdfa.DBHelper.createDataBase(DBHelper.java:62)
        at so.cdfa.DBHelper.<init>(DBHelper.java:36)
        at so.cdfa.MainActivity.onCreate(MainActivity.java:18)
        at android.app.Activity.performCreate(Activity.java:7136)
        at android.app.Activity.performCreate(Activity.java:7127)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:193) 
        at android.app.ActivityThread.main(ActivityThread.java:6669) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 
2019-01-25 17:51:12.330 30371-30371/so.cdfa I/Process: Sending signal. PID: 30371 SIG: 9

Шаг 2 - Запуск после копирования базы данных в папку ресурсов.

Файл базы данных произвольного sqlite, скопированный в папку ресурсов и переименованный в db .База данных копируется, и ее элементы (индексы таблиц и т. Д.) Записываются в журнал, например: -

Снова обратите внимание на версию сборки и ведение журнала

2019-01-25 17:54:51.734 30587-30587/so.cdfa D/VERSION: Build Version is 28
2019-01-25 17:54:51.735 30587-30587/so.cdfa D/COPYDATABASE: Initiated Copy of the database file db from the assets folder.
2019-01-25 17:54:51.735 30587-30587/so.cdfa D/COPYDATABASE: Asset file db found so attmepting to copy to /data/user/0/so.cdfa/databases/db
2019-01-25 17:54:51.736 30587-30587/so.cdfa D/COPYDATABASE: Ateempting copy of block 1 which has 1024 bytes.
............. lines removed from brevity 
2019-01-25 17:54:51.746 30587-30587/so.cdfa D/COPYDATABASE: Ateempting copy of block 40 which has 1024 bytes.
2019-01-25 17:54:51.746 30587-30587/so.cdfa D/COPYDATABASE: Finished copying Database db from the assets folder, to  /data/user/0/so.cdfa/databases/db40960were copied, in 40 blocks of size 1024.
2019-01-25 17:54:51.746 30587-30587/so.cdfa D/COPYDATABASE: All Streams have been flushed and closed.
2019-01-25 17:54:51.770 30587-30587/so.cdfa D/DBCONFIGURE: Database has been configured 
2019-01-25 17:54:51.772 30587-30587/so.cdfa D/DBOPENED: Database has been opened.
2019-01-25 17:54:51.772 30587-30587/so.cdfa D/DBITEMS: Found sqlite_sequence which has a type of table the SQL used to create it, was :-
        CREATE TABLE sqlite_sequence(name,seq)
2019-01-25 17:54:51.773 30587-30587/so.cdfa D/DBITEMS: Found Schedules which has a type of table the SQL used to create it, was :-
        CREATE TABLE `Schedules` (
      `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
      `date` REAL
    )
2019-01-25 17:54:51.773 30587-30587/so.cdfa D/DBITEMS: Found type_affinity_example which has a type of table the SQL used to create it, was :-
        CREATE TABLE type_affinity_example (
        id INTEGER PRIMARY KEY, -- <<<<<<<< MUST BE INTEGER VALUE ELSE INVALID DATATYPE
        col1 rumplestiltskin,
        col2 BLOB,
        col3 INTEGER,
        col4 NUMERIC,
        col5 REAL,
        col6 REALINT, -- because of rule 1 will be INTEGER type affinity NOT REAL!!!!
        col7 TEXT
    )
2019-01-25 17:54:51.773 30587-30587/so.cdfa D/DBITEMS: Found OHLCV_Components which has a type of table the SQL used to create it, was :-
        CREATE TABLE OHLCV_Components (symbol TEXT, tradeDate TEXT, openPrice REAL, highPrice REAL, lowPrice REAL, closePrice REAL, volume INTEGER)
2019-01-25 17:54:51.773 30587-30587/so.cdfa D/DBITEMS: Found league which has a type of table the SQL used to create it, was :-
        CREATE TABLE league (league_id INTEGER PRIMARY KEY, league_name TEXT)
2019-01-25 17:54:51.773 30587-30587/so.cdfa D/DBITEMS: Found team which has a type of table the SQL used to create it, was :-
        CREATE TABLE team (team_id INTEGER PRIMARY KEY, team_name TEXT)
2019-01-25 17:54:51.773 30587-30587/so.cdfa D/DBITEMS: Found player which has a type of table the SQL used to create it, was :-
        CREATE TABLE player (player_id INTEGER PRIMARY KEY, player_name)
2019-01-25 17:54:51.773 30587-30587/so.cdfa D/DBITEMS: Found team_league_history which has a type of table the SQL used to create it, was :-
        CREATE TABLE team_league_history (
        tlh_team_reference INTEGER, 
        tlh_league_reference INTEGER, 
        tlh_from_date TEXT DEFAULT CURRENT_DATE, 
        tlh_to_date TEXT DEFAULT '3000-12-31'
    )
2019-01-25 17:54:51.773 30587-30587/so.cdfa D/DBITEMS: Found player_team_history which has a type of table the SQL used to create it, was :-
        CREATE TABLE player_team_history (
        pth_player_reference INTEGER, 
        pth_team_reference INTEGER, 
        pth_from_date TEXT DEFAULT CURRENT_DATE, 
        pth_to_date TEXT DEFAULT '3000-12-31'
    )
2019-01-25 17:54:51.774 30587-30587/so.cdfa D/DBITEMS: Found android_metadata which has a type of table the SQL used to create it, was :-
        CREATE TABLE android_metadata (locale TEXT)
  • Примечание в простом виде, как указано выше, можно скопировать файл базы данных, не являющийся sqlite (любой файл), который затем приведет к исключению поврежденной базы данных.Проверка первых 16 байтов файла, чтобы определить, соответствуют ли они заголовку файла SQlite ( Строка заголовка: «SQLite format 3 \ 000» ) Формат файла базы данных может устранить эту проблему.

  • Примечание поскольку сама база данных (хотя и пустая) была создана, вам нужно будет удалить ее. Это можно сделать с помощьюудаление данных приложения или удаление приложения (вы также можете удалить его через Device Explorer).

Шаг 3 - Последующий запуск (база данных существует): -

2019-01-25 17:59:32.868 30666-30666/so.cdfa D/VERSION: Build Version is 28
2019-01-25 17:59:32.873 30666-30666/so.cdfa D/DBCONFIGURE: Database has been configured 
2019-01-25 17:59:32.874 30666-30666/so.cdfa D/DBOPENED: Database has been opened.
2019-01-25 17:59:32.875 30666-30666/so.cdfa D/DBITEMS: Found sqlite_sequence which has a type of table the SQL used to create it, was :-
        CREATE TABLE sqlite_sequence(name,seq)
2019-01-25 17:59:32.875 30666-30666/so.cdfa D/DBITEMS: Found Schedules which has a type of table the SQL used to create it, was :-
        CREATE TABLE `Schedules` (
      `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
      `date` REAL
...........
...