Is it possible to move the internal DB to the SDCard?

人走茶凉 提交于 2019-11-28 07:03:10

Just use:

SQLiteDatabase.openDatabase(DB_FULL_PATH, null, SQLiteDatabase.OPEN_READONLY);

where DB_FULL_PATH can be a path to your sdcard, like /sdcard/mydatabase.db

Edit:

This is what I call in my application to access the database....

private static DBUtil dbHelper = null;

public void openDatabase() {
    if(dbHelper == null) {
        dbHelper = new DBUtil(this.context);
        dbHelper.openDataBase(SQLiteDatabase.OPEN_READWRITE);
    }
}
public void closeDatabase() {
    if(dbHelper != null) {
        dbHelper.close();
        dbHelper = null;
    }
}

... and this is the db helper class I'm using, which in fact extends SQLiteOpenHelper, so you will still have everything you want from this class.

package com.myapp.android.db;

import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.myapp.android.MyApp;

import java.io.IOException;

/**
 * Standard database utility class.
 * 
 * TODO: Refactor.
 */
public class DBUtil extends SQLiteOpenHelper {

    /**
     * Database directory.
     * 
     * <p>
     * Example: "/sdcard/myapp/db/"
     * </p>
     */
    public static String DB_DIRECTORY = null;

    /**
     * Name of the database file.
     * 
     * <p>
     * Example: "mydatabase.db"
     * </p>
     * 
     */
    public static String DB_NAME = null;

    /**
     * Full absolute path of the database.
     * 
     * <p>
     * Example: "/sdcard/myapp/db/mydatabase.db"
     * </p>
     */
    public static String DB_FULL_PATH = null;
    static {
        DB_DIRECTORY = MyApp.DATA_REPOSITORY_URI + "/myapp/db/";
        DB_NAME = "mydatabase.db";
        DB_FULL_PATH = DB_DIRECTORY + DB_NAME;
    }

    private SQLiteDatabase myDataBase;

    /**
     * Constructor Takes and keeps a reference of the passed context in order to
     * access to the application assets and resources.
     * 
     * @param context
     */
    public DBUtil(Context context) {
        super(context, DB_NAME, null, 1);

        try {
            this.createDataBase();
        } catch (IOException ioe) {
            throw new Error("Unable to create database");
        }
    }

    /**
     * Creates a empty database on the system and rewrites it with your own
     * database.
     * */
    public void createDataBase() throws IOException {        
        if (!checkDataBase()) this.getWritableDatabase();
    }

    /**
     * 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 {
            checkDB = SQLiteDatabase.openDatabase(DB_FULL_PATH, null,
                    SQLiteDatabase.OPEN_READONLY);
        } catch (SQLiteException e) {
            // database does't exist yet.
        }
        if (checkDB != null) {
            checkDB.close();
        }
        return checkDB != null ? true : false;
    }

    public void openDataBase(int mode) throws SQLException {        
        try {
            myDataBase = SQLiteDatabase.openDatabase(DB_FULL_PATH, null, mode);
        } catch(IllegalStateException e) {
            // Sometimes, esp. after application upgrade, the database will be non-closed, raising a IllegalStateException
            // below. Try to avoid by simply opening it again.
            Log.d(MyApp.APP, "Database non-closed. Reopening.");
            myDataBase = SQLiteDatabase.openDatabase(DB_FULL_PATH, null, mode);
        }
    }

    public void openDataBase() throws SQLException {
        openDataBase(SQLiteDatabase.OPEN_READWRITE);
    }

    public SQLiteDatabase getDb() {
        return myDataBase;
    }

    @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) {
    }

}

I found I could use a full path in Android 2.2, but in 2.1 the Context.openOrCreateDatabase() method threw an exception. To work around this I wrapped that method to call SQLiteDatabase.openOrCreateDatabase() directly. Here is the constructor for my extended SQLOpenHelper

public class Database extends SQLiteOpenHelper {
  public Database(Context context) {
    super(new ContextWrapper(context) {
        @Override public SQLiteDatabase openOrCreateDatabase(String name, 
                int mode, SQLiteDatabase.CursorFactory factory) {

            // allow database directory to be specified
            File dir = new File(DIR);
            if(!dir.exists()) {
                dir.mkdirs();
            }
            return SQLiteDatabase.openDatabase(DIR + "/" + NAME, null,
                SQLiteDatabase.CREATE_IF_NECESSARY);
        }
    }, NAME, null, VERSION);
    this.context = context;
  }
}
    String dbPath = DATABASE_NAME;
    File sdcard = Environment.getExternalStorageDirectory();
    if (sdcard != null && sdcard.canWrite()){
        dbPath = sdcard.getAbsolutePath() + "/mypath/onsdcard/" + DATABASE_NAME;
    }
    else {
        dbPath = DATABASE_NAME;
    }
    mDBHelper  = new WorkoutDBOpenHelper(context, dbPath);
    if(null != mDBHelper)
        mDB = mDBHelper.getWritableDatabase();

For me this works, and WorkoutDBOpenHelper extends SQLiteOpenHelper and its constructor simply calls super for SQLiteOpenHelper.

WorkoutDBOpenHelper(Context context, String dbPath) {
    super(context, dbPath, null, DATABASE_VERSION);

}

Please note that SQLiteopenHelper creates the database on the memory card too. However, on app uninstall, the DB will not be deleted from the sdcard.

This is not the answer for how to move an existing internal DB to SDCard, but this way you can choose one option at the creation time. I am working on moving the already existing database from app's "data" directory to sdcard, but there is no direct way. Will update once I figure out something.

Pyae Sone

This will be ok. I thought

public class MainActivity extends Activity {

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

    Log.i("DATABASE EXIST : ", ""+checkDataBase());
    if(!checkDataBase())
        copyDataBase();

    DatabaseHandler dbhandler = new DatabaseHandler(MainActivity.this);
    Cursor cursor = dbhandler.getAllContacts();

    ListView list = (ListView) findViewById(R.id.datalist);
    CustomCursorAdapter cursoradapter = new CustomCursorAdapter(MainActivity.this, cursor);
    list.setAdapter(cursoradapter);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}

private void copyDataBase()
{
    ContextWrapper cw =new ContextWrapper(getApplicationContext());
    String DB_PATH = "/data/data/com.example.copydatabase/databases/";
    String DB_NAME = "testing";

    Log.i("Database", "New database is being copied to device!");
    byte[] buffer = new byte[1024];
    OutputStream myOutput = null;
    int length;
    // Open your local db as the input stream
    InputStream myInput = null;
    try
    {
        myInput = MainActivity.this.getAssets().open(DB_NAME);
        // transfer bytes from the inputfile to the
        // outputfile
        myOutput =new FileOutputStream(DB_PATH+ DB_NAME);
        while((length = myInput.read(buffer)) > 0)
        {
            myOutput.write(buffer, 0, length);
        }
        myOutput.close();
        myOutput.flush();
        myInput.close();
        Log.i("Database", "New database has been copied to device!");

    }
    catch(IOException e)
    {
        e.printStackTrace();
    }
}

public boolean checkDataBase()
{
    String DB_PATH = "/data/data/com.example.copydatabase/databases/";
    String DB_NAME = "testing";
    File dbFile = new File(DB_PATH + DB_NAME);
    return dbFile.exists();
}
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!