Как скопировать базу данных из внутреннего хранилища во внешнее хранилище (предположим, что это папка для скачивания)? - PullRequest
0 голосов
/ 11 июля 2019

В моем приложении есть база данных, созданная sqlite. Я хочу скопировать базу данных в папку для скачивания. Я использовал другой способ, но не работал в реальном устройстве (скажем, запрет доступа к каталогу), может быть, он хочет рутированный телефон. Пожалуйста, помогите, я хочу дать доступ, чтобы пользователь мог получить базу данных из папки загрузки.

Обратите внимание, что я использую последнюю версию Android Studio.

В приведенном ниже классе DatabaseHelper. В методе exportDB () я хочу реализовать это.

package com.tarikul.sqlitedatabase1;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Environment;
import android.widget.Toast;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;

public class DatabaseHelper extends SQLiteOpenHelper {
    private static final String DATABASE_NAME = "Students.db";
    private static final String TABLE_NAME = "student_details";
    private static final String ID = "_id";
    private static final String NAME = "Name";
    private static final String AGE = "Age";
    private static final String GENDER = "Gender";
    private static final int  VERSION_NUMBER = 1;
    private static final String CREATE_TABLE = "CREATE TABLE "+TABLE_NAME+"("+ID+" INTEGER PRIMARY KEY AUTOINCREMENT, "+NAME+" VARCHAR(155), "+AGE+" INTEGER, "+GENDER+" VARCHAR(15));";
    private static final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLE_NAME;
    private static final String SELECT_ALL_DATA = "SELECT * FROM " + TABLE_NAME;

    private Context context;

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, VERSION_NUMBER);
        this.context=context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        try {
            db.execSQL(CREATE_TABLE);
            Toast.makeText(context,"OnCreate is called.",Toast.LENGTH_SHORT).show();
        }catch (Exception e){
            Toast.makeText(context,"Exception: "+e,Toast.LENGTH_SHORT).show();
        }


    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        try {
            Toast.makeText(context,"onUpgrade is called.",Toast.LENGTH_SHORT).show();
            db.execSQL(DROP_TABLE);
            onCreate(db);

        }catch (Exception e){
            Toast.makeText(context,"Exception: "+e,Toast.LENGTH_SHORT).show();
        }

    }

    public long insert(String name, String age, String gender)
    {
        SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
        ContentValues contentValues = new ContentValues();
        contentValues.put(NAME,name);
        contentValues.put(AGE,age);
        contentValues.put(GENDER,gender);
        long rowId = sqLiteDatabase.insert(TABLE_NAME,null,contentValues);
        return rowId;
    }

    public Cursor displayAllData(){
        SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
        Cursor cursor = sqLiteDatabase.rawQuery(SELECT_ALL_DATA,null);
        return cursor;
    }

    public boolean updateData(String id, String name, String age, String gender)
    {
        SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
        ContentValues contentValues = new ContentValues();
        contentValues.put(ID,id);
        contentValues.put(NAME,name);
        contentValues.put(AGE,age);
        contentValues.put(GENDER,gender);

        sqLiteDatabase.update(TABLE_NAME, contentValues,ID + " = ?",new String[]{id});
        return true;
    }

    public int deleteData(String id)
    {
        SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
        return sqLiteDatabase.delete(TABLE_NAME,ID + " = ?", new String[]{id});
    }

    public void exportDB()
    {

    }

}

1 Ответ

1 голос
/ 11 июля 2019

Короче надо

1. получить разрешение WRITE_EXTERNAL_STORAGE

  • В манифесте есть: - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

  • и, если версия сборки 23 или выше, проверьте / запросите ее во время выполнения, например, Я использую: -

    if(Build.VERSION.SDK_INT >= 23) {
        ExternalStoragePermissions.verifyStoragePermissions(this);
    }
    

вместе с: -

class ExternalStoragePermissions {

    public int API_VERSION = Build.VERSION.SDK_INT;
    private static final int REQUEST_EXTERNAL_STORAGE = 1;
    private static String[] PERMISSIONS_STORAGE = {

            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };

    public ExternalStoragePermissions() {}
    // Note call this method
    public static void verifyStoragePermissions(Activity activity) {

        int permission = ActivityCompat.checkSelfPermission(
                activity,
                Manifest.permission.WRITE_EXTERNAL_STORAGE);

        if(permission != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(
                    activity,
                    PERMISSIONS_STORAGE,
                    REQUEST_EXTERNAL_STORAGE
            );
        }
    }
}
  • Обратите внимание, что вышеизложенное должно быть сделано при первом запуске приложения.

2. Подготовьте базу данных

Вы должны закрыть базу данных или, по крайней мере, проверить ее, если она использует запись в журнал (WAL). В режиме WAL транзакции (обновления / вставки / удаления) хранятся в файлах -wal и -shm, только когда эти транзакции зафиксированы (закрыты или полностью проверены), часть базы данных не хранится в этих файлах, поэтому вам необходимо данные.

В режиме журнала изменения, внесенные в базу данных, сохраняются в файле -journal. Их можно использовать для отката изменений, внесенных в базу данных (откат в WAL приводит к удалению изменений из файлов -wal и -shm, поэтому они никогда не применяются к файлу базы данных) .

Следующий метод, добавленный к вам DatabaseHelper Класс будет проверять базу данных в случае необходимости: -

private void checkpointIfWALEnabled(Context context, String databaseName) {
    Cursor csr;
    int wal_busy = -99, wal_log = -99, wal_checkpointed = -99;
    SQLiteDatabase db = SQLiteDatabase.openDatabase(context.getDatabasePath(databaseName).getPath(), null, SQLiteDatabase.OPEN_READWRITE);
    csr = db.rawQuery("PRAGMA journal_mode", null);
    if (csr.moveToFirst()) {
        String mode = csr.getString(0);
        if (mode.toLowerCase().equals("wal")) {
            csr = db.rawQuery("PRAGMA wal_checkpoint", null);
            if (csr.moveToFirst()) {
                wal_busy = csr.getInt(0);
                wal_log = csr.getInt(1);
                wal_checkpointed = csr.getInt(2);
            }
            csr = db.rawQuery("PRAGMA wal_checkpoint(TRUNCATE)", null);
            csr.getCount();
            csr = db.rawQuery("PRAGMA wal_checkpoint", null);
            if (csr.moveToFirst()) {
                wal_busy = csr.getInt(0);
                wal_log = csr.getInt(1);
                wal_checkpointed = csr.getInt(2);
            }
        }
    }
    csr.close();
    db.close();
}

3. Сделать экспорт

например. Ниже приведен пример кода ядра, который вы можете использовать

        public void exportDB() {

            this.getWritableDatabase().close();
            try {
                String dbfilename = this.getDatabasePath(DATABASE_NAME).getPath();
                File dbfile = new File(dbfilename);
                String backupfilename = (new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),null)).getPath() + File.separator + DATABASE_NAME + "-backup";
                checkpointIfWALEnabled(context,DATABASE_NAME);
                FileInputStream fis = new FileInputStream(dbfile);
                OutputStream backup = new FileOutputStream(backupfilename);
                String methodname = new Object() {
                }.getClass().getEnclosingMethod().getName();

                byte[] buffer = new byte[32768]; //32k buffer, may be changed
                int length;
                while ((length = fis.read(buffer)) > 0) {
                    backup.write(buffer, 0, length);
                }
                backup.flush();
                backup.close();
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
  • Обратите внимание, что приведенный выше код извлечен из работы с более сложным кодом и немного изменен. Он не был протестирован или запущен, поэтому возможны незначительные ошибки.
  • Я бы предположил, что добавление -backup ограничит вас одним файлом, вы можете включить временную метку, чтобы вы могли создавать несколько резервных копий.
...