61

I'd like to add a feature to my Android app that automatically backs up the SQLite database to the SD card.

What's the best way to go about this? Are any examples or tutorials available?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
CodeFusionMobile
  • 14,812
  • 25
  • 102
  • 140

10 Answers10

124

This code works for me!

    try {
        File sd = Environment.getExternalStorageDirectory();
        File data = Environment.getDataDirectory();

        if (sd.canWrite()) {
            String currentDBPath = "//data//{package name}//databases//{database name}";
            String backupDBPath = "{database name}";
            File currentDB = new File(data, currentDBPath);
            File backupDB = new File(sd, backupDBPath);

            if (currentDB.exists()) {
                FileChannel src = new FileInputStream(currentDB).getChannel();
                FileChannel dst = new FileOutputStream(backupDB).getChannel();
                dst.transferFrom(src, 0, src.size());
                src.close();
                dst.close();
            }
        }
    } catch (Exception e) {
    }

Does anyone know if this will work on non-root phones? I have only tried it on a rooted G1.

sajal
  • 776
  • 1
  • 6
  • 23
skeniver
  • 2,647
  • 6
  • 28
  • 34
  • 19
    I can confirm this does work on non-rooted phones. Just make sure you add `` – Jake Wilson Nov 01 '11 at 14:39
  • currentDB.exists() returnign false.... might b that database is not present on the sys memory but I have successfull insert the rows...and m getting the path by String currentDBPath = db.getPath(); – Inder Kumar Rathore Jan 11 '12 at 06:19
  • 10
    I use File currentDB = getDatabasePath(DatabaseHelper.DATABASE_NAME); rather than a static referance – Quintin Balsdon Feb 04 '12 at 16:33
  • FileChannel src = new FileOutputStream(currentDB).getChannel(); FileChannel dst = new FileInputStream(backupDB).getChannel(); src.transferFrom(dst, 0, dst.size()); src.close(); dst.close(); when i do this the db is getting lost and creating a new file – Sandeep P May 01 '13 at 11:50
  • and restore bd, how would it be? for not root devices – angel Aug 16 '13 at 20:13
21
try {
    File sd = Environment.getExternalStorageDirectory();
    File data = Environment.getDataDirectory();

    if (sd.canWrite()) {
        String currentDBPath = "//data//"+ packageName +"//databases//"+dbList[0];
        String backupDBPath = dbList[0];
        File currentDB = new File(data, currentDBPath);
        File backupDB = new File(sd, backupDBPath);

        FileChannel src = new FileInputStream(currentDB).getChannel();
        FileChannel dst = new FileOutputStream(backupDB).getChannel();
        dst.transferFrom(src, 0, src.size());
        src.close();
        dst.close();
        Toast.makeText(getBaseContext(), backupDB.toString(), Toast.LENGTH_LONG).show();
    }
} catch (Exception e) {
    Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG).show();
}

That works as opposed to the above examples in which the "/" are "\" wasted 20 minutes of my life figuring that out, but I really should have seen that sooner. The Toast will tell you where the file has been place or tell you what's wrong when it doesn't work.

Andrew T.
  • 4,701
  • 8
  • 43
  • 62
Rhys
  • 219
  • 2
  • 2
  • 1
    iif(sd.canWrite()) did not work for me. Instead i used if (Environment.MEDIA_MOUNTED.equals(state)) { – Archie Apr 08 '14 at 16:22
10

SQLite databases are completely self-contained files and are portable — you can just copy the entire file straight to the SD card.

Though first I'd check whether an SD card is installed in the device, and what its path is (using Environment.getExternalStorageDirectory()).

Christopher Orr
  • 110,418
  • 27
  • 198
  • 193
3
public static void BackupDatabase() throws IOException
{
    boolean success =true;
    File file = null;
    file = new File(Environment.getExternalStorageDirectory() +"/M.O.L.S_Backup");

    if (file.exists())
    {
        success =true;
    }
    else
    {
        success = file.mkdir();
    }

    if (success)
    {
        String inFileName = "/data/data/com.sygic.sdk.demo/databases/MOLS_DB.s3db";
        File dbFile = new File(inFileName);
        FileInputStream fis = new FileInputStream(dbFile);

        String outFileName = Environment.getExternalStorageDirectory()+"/M.O.L.S_Backup/MOLS_DB.s3db";

        // Open the empty db as the output stream
        OutputStream output = new FileOutputStream(outFileName);

        // Transfer bytes from the inputfile to the outputfile
        byte[] buffer = new byte[1024];
        int length;
        while ((length = fis.read(buffer))>0) {
            output.write(buffer, 0, length);
        }

        output.flush();
        output.close();
        fis.close();
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Osama Ibrahim
  • 995
  • 10
  • 13
3

I answered a question similar to this with a method you can place in your SQLiteOpenHelper. It is as simple as copying the db file from some kind of external storage, to the internal application storage. There is also some extra code that opens and reads the db file to make sure it is in the proper state for Android to make database calls to it.

Community
  • 1
  • 1
Austyn Mahoney
  • 11,398
  • 8
  • 64
  • 85
  • I saw your example and it looks concise, like too concise. Its hard for me to figure out how to adapt it to my code. I don't know who's code is more efficient, all I know is that extra logic/code or too simplified of code makes it harder for me to understand and adapt to my code. Most people create 4 separate "FILE"s, while yours only create 2 FILEs. Why is this particular topic so confusing? – JamisonMan111 May 24 '17 at 02:26
2

You have to give the permission android.permission.WRITE_EXTERNAL_STORAGE in your application. It works fine on unrooted devices.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
1

You find your Database Name in the Database Adapter if you are new into this.

Note that you can do this for SharedPreferences too but keep in mind to change your Context.MODE_PRIVATE to Context.MODE_MULTI_PROCESS.

SharedPreferences_name should look like this = ExportSP("temp.xml");

String currentPathForSharedPreferences = "/data/"+ context.getPackageName() +"/shared_prefs/"+ SharedPreferences_name;

For export

exportDB("MyDbName");

private void exportDB(String db_name){

File sd = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + 
                File.separator + "Your Backup Folder"+ 
                File.separator );

          boolean success = true;
           if (!sd.exists()) {
               success = sd.mkdir();
           }
           if (success) {

        File data = Environment.getDataDirectory();
       FileChannel source=null;
       FileChannel destination=null;
       String currentDBPath = "/data/"+ context.getPackageName() +"/databases/"+db_name;
       String backupDBPath = db_name;
       File currentDB = new File(data, currentDBPath);
       File backupDB = new File(sd, backupDBPath);
       try {
            source = new FileInputStream(currentDB).getChannel();
            destination = new FileOutputStream(backupDB).getChannel();
            destination.transferFrom(source, 0, source.size());
            source.close();
            destination.close();
            Toast.makeText(this, "Please wait", Toast.LENGTH_SHORT).show();
        } catch(IOException e) {
            e.printStackTrace();
        }
           }}

For import

importDB("MyDbName");

private void importDB(String db_name){
        File sd = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + 
                File.separator + "Your Backup Folder"+ 
                File.separator );
        File data = Environment.getDataDirectory();
       FileChannel source=null;
       FileChannel destination=null;
       String backupDBPath = "/data/"+ context.getPackageName() +"/databases/"+db_name;
       String currentDBPath = db_name;
       File currentDB = new File(sd, currentDBPath);
       File backupDB = new File(data, backupDBPath);
       try {
            source = new FileInputStream(currentDB).getChannel();
            destination = new FileOutputStream(backupDB).getChannel();
            destination.transferFrom(source, 0, source.size());
            source.close();
            destination.close();
            Toast.makeText(this, "Please wait", Toast.LENGTH_SHORT).show();
        } catch(IOException e) {
            e.printStackTrace();
        }
}
ORY
  • 393
  • 1
  • 4
  • 11
1

I don't know what happens if the phone is rooted or not but you should write your files to:

/Android/data/{package_name}/files/

This will work whether it's rooted or not.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
JMA
  • 1,781
  • 9
  • 18
  • 3
    The problem with backing up to this location on the sd-card is that it is deleted when the app is uninstalled. That might not be wanted for a backup. – ZNS Dec 21 '12 at 09:38
1

@skeniver's code works for me. I just want to add the following:

Use:

String currentDbPath = getApplicationContext().getDatabasePath("{database name}");

It will give you your database path. It is better to use that instead of hardcoding the path, like:

String currentDbPath = "//data//{package name}//databases//{database name}";
Adinia
  • 3,722
  • 5
  • 40
  • 58
-1
@Override
protected void onCreate(Bundle savedInstanceState) {
    try {
        File sd = Environment.getExternalStorageDirectory();
        File data = Environment.getDataDirectory();

        if (sd.canWrite()) {
            String currentDBPath = "//data//"+getPackageName()+"//databases//"+DATABASE_NAME+"";
            String backupDBPath = "backup.db";
            File currentDB = new File(data, currentDBPath);
            File backupDB = new File(sd, backupDBPath);

            FileChannel src = new FileInputStream(currentDB).getChannel();
            FileChannel dst = new FileOutputStream(backupDB).getChannel();
            dst.transferFrom(src, 0, src.size());
            src.close();
            dst.close();
            Toast.makeText(getBaseContext(), backupDB.toString(), Toast.LENGTH_LONG).show();
        }
    } catch (Exception e) {
        Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG).show();
    }
}
Quintin Balsdon
  • 5,484
  • 10
  • 54
  • 95