如何将数据库从内部存储复制到外部存储(假设是下载文件夹)?

时间:2019-07-11 10:22:47

标签: android android-sqlite

在我的应用程序中,有一个由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 个答案:

答案 0 :(得分:1)

简而言之,您需要

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会将您限制为仅一个这样的文件,您可能希望包括时间戳记,以便可以进行多个备份。