是否可以将内部数据库移动到SD卡?

随着我的应用程序中的数据库的增长,它将需要越来越多的内部手机空间。 数据库中没有任何敏感/私人数据,所以我有兴趣将其移动到SD卡。

我正在使用SQLiteOpenHelper来协助数据库工作。 我的理解是,您不能将其用于SD卡上的DB访问,因为您无法定义数据库路径。 但是,Internet上有一些(非常差的)示例表明您可以覆盖此限制。 但是我从来没有得到其中一个代码示例来编译。

可能吗? 如果是这样 – 怎么样! 请注意,Froyo的“SD卡上的应用程序”function不起作用,因为它不会移动内部文件。

只需使用:

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

其中DB_FULL_PATH可以是sdcard的路径,例如/sdcard/mydatabase.db

编辑:

这是我在我的应用程序中调用以访问数据库….

 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; } } 

…这是我正在使用的db帮助程序类,它实际上扩展了SQLiteOpenHelper,因此您仍然可以从此类中获得所需的一切。

 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. * * 

* Example: "/sdcard/myapp/db/" *

*/ public static String DB_DIRECTORY = null; /** * Name of the database file. * *

* Example: "mydatabase.db" *

* */ public static String DB_NAME = null; /** * Full absolute path of the database. * *

* Example: "/sdcard/myapp/db/mydatabase.db" *

*/ 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) { } }

我发现我可以在Android 2.2中使用完整路径,但在2.1中,Context.openOrCreateDatabase()方法引发了exception。 为了解决这个问题,我将该方法包装成直接调用SQLiteDatabase.openOrCreateDatabase()。 这是我的扩展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(); 

对我来说这很有用,WorkoutDBOpenHelper扩展了SQLiteOpenHelper,它的构造函数只是为SQLiteOpenHelper调用super。

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

请注意,SQLiteopenHelper也会在存储卡上创建数据库。 但是,在应用程序卸载时,不会从SD卡中删除数据库。

这不是如何将现有内部数据库移动到SDCard的答案,但这样您可以在创建时选择一个选项。 我正在努力将已经存在的数据库从应用程序的“数据”目录移动到SD卡,但没有直接的方法。 一旦我find了什么就会更新。

这没关系。 我想

 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(); } }