21

I am trying to copy DB from assets folder to device. This code is working fine on Emulator and rooted Device. I just want to know is it create any problem on unrooted device or it will work same.

private void StoreDatabase() {
    File DbFile = new File(
            "data/data/packagename/DBname.sqlite");
    if (DbFile.exists()) {
        System.out.println("file already exist ,No need to Create");
    } else {
        try {
            DbFile.createNewFile();
            System.out.println("File Created successfully");
            InputStream is = this.getAssets().open("DBname.sqlite");
            FileOutputStream fos = new FileOutputStream(DbFile);
            byte[] buffer = new byte[1024];
            int length = 0;
            while ((length = is.read(buffer)) > 0) {
                fos.write(buffer, 0, length);
            }
            System.out.println("File succesfully placed on sdcard");
            // Close the streams
            fos.flush();
            fos.close();
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
Krishnakant Dalal
  • 3,568
  • 7
  • 34
  • 62

6 Answers6

18

This will work for sure in all devices and emulator, no need to root.

/**
 * Copies your database from your local assets-folder to the just created
 * empty database in the system folder, from where it can be accessed and
 * handled. This is done by transfering bytestream.
 * */
private void copyDataBase(String dbname) throws IOException {
    // Open your local db as the input stream
    InputStream myInput = myContext.getAssets().open(dbname);
    // Path to the just created empty db
    File outFileName = myContext.getDatabasePath(dbname);
    // Open the empty db as the output stream
    OutputStream myOutput = new FileOutputStream(outFileName);
    // transfer bytes from the inputfile to the outputfile
    byte[] buffer = new byte[1024];
    int length;
    while ((length = myInput.read(buffer)) > 0) {
        myOutput.write(buffer, 0, length);
    }
    // Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();
}
Sufian
  • 6,405
  • 16
  • 66
  • 120
abbas.aniefa
  • 2,855
  • 21
  • 30
  • My code is also working fine I just want to know is it create any problem on unrooted device ? – Krishnakant Dalal May 25 '12 at 04:44
  • 15
    **NEVER HARDCODE PATHS**. The `outFileName` value will be wrong on many Android environments, such as secondary accounts. Use `getDatabasePath()` to derive the path for a database file. – CommonsWare Oct 18 '14 at 20:05
  • Thanks @CommonsWare . I will change it to `String outFileName = getDatabasePath() + dbname;` – abbas.aniefa Oct 20 '14 at 11:54
  • 3
    Should this not be myContext.getDatabasePath(dbname)? Also getDatabasePath(dbName) returns a file object not a String. – Andrew S Jan 16 '16 at 06:31
  • This seems to result in an export of an encrypted database file (see question - https://stackoverflow.com/questions/44397083/android-copy-and-export-application-db-results-in-encrypted-db-on-unrooted-ph) – Garbit Jun 06 '17 at 18:20
6
    /**
 * Copy database file from assets folder inside the apk to the system database path.
 * @param context Context
 * @param databaseName Database file name inside assets folder
 * @param overwrite True to rewrite on the database if exists
 * @return True if the database have copied successfully or if the database already exists without overwrite, false otherwise.
 */
private boolean copyDatabaseFromAssets(Context context, String databaseName , boolean overwrite)  {

    File outputFile = context.getDatabasePath(databaseName);
    if (outputFile.exists() && !overwrite) {
        return true;
    }

    outputFile = context.getDatabasePath(databaseName + ".temp");
    outputFile.getParentFile().mkdirs();

    try {
        InputStream inputStream = context.getAssets().open(databaseName);
        OutputStream outputStream = new FileOutputStream(outputFile);


        // transfer bytes from the input stream into the output stream
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) > 0) {
            outputStream.write(buffer, 0, length);
        }

        // Close the streams
        outputStream.flush();
        outputStream.close();
        inputStream.close();

        outputFile.renameTo(context.getDatabasePath(databaseName));

    } catch (IOException e) {
        if (outputFile.exists()) {
            outputFile.delete();
        }
        return false;
    }

    return true;
}
Mahmoud
  • 2,683
  • 1
  • 30
  • 32
  • 1
    I gave a +1 because the combination of getDatabasePath() method of the context object and outputFile.getParentFile().mkdirs() of your code solved my problem in which the database copying was failing when I used the hard-coded directory path that other examples show. – Casey Perkins Apr 22 '15 at 14:50
1

I am not sure, but this works on every device I have tested on. I stole this method (from somewhere here) and made it generic for both backing up and restoring:

public static void movedb(File srcdb, File destdb)
{
    try 
    {
        if (Environment.getExternalStorageDirectory().canWrite()) 
        {                 
            if (srcdb.exists()) 
            {
                FileChannel src = new FileInputStream(srcdb).getChannel();
                FileChannel dst = new FileOutputStream(destdb).getChannel();
                dst.transferFrom(src, 0, src.size());
                src.close();
                dst.close();                    
            }
            else
            {
                //ERROR: "Database file references are incorrect"                    
            }
        }
        else
        {
           //ERROR: "Cannot write to file"
        }
    }
    catch (Exception e) 
    {
        //ERROR: e.getMessage()
    }
}

Then I just back it up by calling:

movedb(this, getDatabasePath(getDbName()), new File(Environment.getExternalStorageDirectory(), getDatabaseBackupPath()));

Where getDatabasePath() and getDatabaseBackupPath() are just string values

Deepzz
  • 4,573
  • 1
  • 28
  • 52
Quintin Balsdon
  • 5,484
  • 10
  • 54
  • 95
0
private void copyDataBase(Context context) throws IOException {

    //Log.i(TAG, "Opening Asset...");
    // Open your local db as the input stream
    InputStream myInput = context.getAssets().open(DBHelper.DATABASE_NAME);

   // Log.i(TAG, "Getting db path...");
    // Path to the just created empty db
    File dbFile = getDatabasePath(DBHelper.DATABASE_NAME);

    if (!dbFile.exists()) {
        SQLiteDatabase checkDB = context.openOrCreateDatabase(DBHelper.DATABASE_NAME, context.MODE_PRIVATE, null);
        if (checkDB != null) {
            checkDB.close();
        }
    }

    //Log.i(TAG, "Getting output stream...");
    // Open the empty db as the output stream
    OutputStream myOutput = new FileOutputStream(dbFile);

  //  Log.i(TAG, "Writing data...");
    // transfer bytes from the inputfile to the outputfile
    byte[] buffer = new byte[1024];
    int length;
    while ((length = myInput.read(buffer)) > 0) {
        myOutput.write(buffer, 0, length);
    }
    // Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();
}
Misa Lazovic
  • 2,805
  • 10
  • 32
  • 38
0

This works for Kotlin.

assets.open("sqlite_db_in_assets.db")
      .copyTo(getDatabasePath("sqlite_db_in_device.db").outputStream())
arjunaskykok
  • 946
  • 10
  • 17
-1

While technically feasible, I don't believe copying (either to or from) potentially live database file is a good idea.

Srg
  • 510
  • 4
  • 13
  • This should probably be a comment instead. Why do you think it deserves to be an answer? – Dharman Aug 13 '19 at 11:43
  • @Dharman Because if correct, it justifies closing the whole question marking it "bad practice". Not sure how it works here... – Srg Aug 13 '19 at 11:46
  • The way it works here is that we post such remarks as comments under the question unless they answer the question directly. If it is a bad practice you should warn them about it, but they might still want the question to be answered anyway. – Dharman Aug 13 '19 at 11:48
  • You see, this is an actual question I'm looking an answer for. To me this smells like a bad question with bad answers. I'm not a moderator so closing stuff is not up to me, but it's also not a mere comment I'm making here. But do feel free to cast your vote. – Srg Aug 13 '19 at 11:51
  • Ok, then let me give you an advice. If you would like to keep this as answer, then explain a little bit more why do you think it is not a good idea. Currently your answer looks nothing more than a personal opinion without any back up. – Dharman Aug 13 '19 at 11:54
  • 1
    Aha :) Once I wrap my head around wal_checkpoint, I'll come back and elaborate. If I have time that is. Until then I'm offering 25 years of sysadm and programming experience intuition. The reader is welcome to take it or leave it. – Srg Aug 13 '19 at 12:16