Скопированная база данных Java Android неполна

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

здесь код фреймворка databasehelper:

package com.example.chiffrage;

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 android.util.Log;
import android.widget.TextView;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;


public class DataBaseHelper extends SQLiteOpenHelper {

    String DB_PATH = null;
    private static String DB_NAME = "ChiffrageBDD.db";
    private SQLiteDatabase myDataBase;
    private final Context myContext;

    public DataBaseHelper(Context context) {
        super(context, DB_NAME, null, 10);
        this.myContext = context;
        this.DB_PATH = context.getApplicationInfo().dataDir + "/";
        Log.e("Path 1", DB_PATH);
    }


    public void createDataBase() throws IOException {
        boolean dbExist = checkDataBase();
        if (dbExist) {
        } else {
            this.getReadableDatabase();
            try {
                copyDataBase();
            } catch (IOException e) {
                throw new Error("Error copying database");
            }
        }
    }

    private boolean checkDataBase() {
//        SQLiteDatabase checkDB = null;
//        try {
//            String myPath = DB_PATH + DB_NAME;
//            checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
//        } catch (SQLiteException e) {
//        }
//        if (checkDB != null) {
//            checkDB.close();
//        }
//        return checkDB != null ? true : false;
        File databasePath = myContext.getDatabasePath(DB_NAME);
        return databasePath.exists();
    }

    private void copyDataBase() throws IOException {
        InputStream myInput = myContext.getAssets().open(DB_NAME);
        String outFileName = DB_PATH + DB_NAME;
        OutputStream myOutput = new FileOutputStream(outFileName);
        byte[] buffer = new byte[2068];
        int length;
        while ((length = myInput.read(buffer)) > 0) {
            myOutput.write(buffer, 0, length);
        }
        myOutput.flush();
        myOutput.close();
        myInput.close();

    }

    public void openDataBase() throws SQLException {
        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) {
        if (newVersion > oldVersion)
            try {
                copyDataBase();
            } catch (IOException e) {
                e.printStackTrace();

            }
    }

    public List getAllMetal(){
        List returnList = new ArrayList();
        String queryString = "PRAGMA table_info(Metal)";
        SQLiteDatabase db = this.getReadableDatabase();
        Cursor cursor = db.rawQuery(queryString, null);
        if (cursor.moveToFirst()){
            do {
                returnList.add(cursor.getString(1));
            } while (cursor.moveToNext());
            } else {
            //failure
        }
        cursor.close();
        db.close();
        return returnList;
    }
}

Ответ getAllMetal: [ID] у меня должно быть имя таблицы Metal с идентификатором, а nom nom — это название металла. данных нет, и я использовал PRAGMA для проверки столбца, и, как вы видите, отсутствует столбец nom.

вот некоторые ресурсы, где я получил код:

[Структура SQLiteOpenHelper] https://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper#SQLiteOpenHelper(android.content.Context,%20java.lang.String,%20android.database.sqlite.SQLiteDatabase.CursorFactory,%20int)

[Копировать базу данных] Ошибка получения чтобы открыть ошибку базы данных при копировании базы данных sqlite из ресурсов в Android 4.2

спасибо за ваше время.


person pierre LERICHE    schedule 09.03.2021    source источник
comment
Где находится ваша заполненная база данных, когда вы пытаетесь ее скопировать? А куда ты хочешь скопировать?   -  person blackapps    schedule 09.03.2021


Ответы (1)


Использование PRAGMA table_info(Metal) не приведет к сбою, если таблица не существует. Вместо этого он не будет показывать строки. Поэтому это может ввести в заблуждение и, вероятно, вводит в заблуждение вас.

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

Я подозреваю, что у вас возникли проблемы, и вы непреднамеренно создали пустую базу данных (что касается пользовательских таблиц). Это позволит вам вызвать getAllMetal и получить результат, который вы сказали.

Другая проблема заключается в том, что DB_PATH при использовании this.DB_PATH = context.getApplicationInfo().dataDir + "/"; не будет таким же, как File databasePath = myContext.getDatabasePath(DB_NAME);. они будут

  • /data/data/‹the_package_name›/ChiffrageBDD.db и
  • /data/data/<the_package_name>/databases/ChiffrageBDD.db
    • <the_package_name> reflecting the package name used

Случайно создать пустую базу данных на Android довольно легко, поэтому я подозреваю, что наличие пустой базы данных является вашей проблемой. После создания база данных сохраняется (всегда существует, если вы не удалите ее специально), что также может быть частью проблемы (проблем).

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

У вашего DataBaseHelper есть проблема, заключающаяся в том, что он не поддерживает новую установку приложения. Когда приложение установлено, каталог /data/data/‹package_name› существует, НО каталог databases не существует. В этом случае метод copyDataBase завершится ошибкой, поскольку каталог баз данных не существует.

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

public class DBAssetHelper2 extends SQLiteOpenHelper {

    static String DATABASE_NAME = "databasefile2";

    public DBAssetHelper2(Context context) {
        super(context, DATABASE_NAME, null, 1);
        String databasePath = context.getDatabasePath(DATABASE_NAME).getPath();
        if (!doesDatabaseExist(databasePath)) {
            copyDatabaseFromAssets(context,databasePath,DATABASE_NAME);
        }
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }

    // Checks to see if the database exists, if it does not
    // then checks to see if the directories in the path exist
    // and then makes the directories if they do not
    private boolean doesDatabaseExist(String databasepath) {
        if (new File(databasepath).exists()) return true;
        if (new File(databasepath).getParentFile().exists()) return false;
        new File(databasepath).getParentFile().mkdirs();
        return false;
    }

    private void copyDatabaseFromAssets(Context context, String databasepath, String assetfilename) {
        int bSize = 4096, bytes = 0;
        byte[] buffer = new byte[bSize];
        try {
            InputStream asset = context.getAssets().open(assetfilename);
            FileOutputStream database = new FileOutputStream(new File(databasepath));
            while((bytes = asset.read(buffer)) > 0) {
                database.write(buffer,0,bytes);
            }
            database.flush();
            database.close();
            asset.close();

        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("Error copying Asset File " + assetfilename + " to " + databasepath);
        }
    }
}

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

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

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

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

ВАЖНО После внесения предложенных изменений вы ОБЯЗАНЫ удалить существующую (вероятно, пустую) базу данных. Самый простой способ — удалить приложение, а затем запустить приложение.

Ниже приведен пример того, как вы могли бы использовать вышеуказанное в действии: -

public class MainActivity extends AppCompatActivity {

    DBAssetHelper2 dbAssetHelper2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        dbAssetHelper2 = new DBAssetHelper2(this);
        Cursor cursor2 = dbAssetHelper2.getReadableDatabase().query("sqlite_master",null,null,null,null,null,null);
        DatabaseUtils.dumpCursor(cursor2);
        cursor2.close();
    }
}

Обратите внимание, что код после создания экземпляра извлекает все строки из таблицы sqlite_master и, таким образом, отображает все таблицы в базе данных. Результат будет отображаться в журнале.

person MikeT    schedule 09.03.2021