Copy Database from assets folder in unrooted device
Asked Answered
M

6

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

}
Macron answered 24/5, 2012 at 13:38 Comment(1)
Yes your code snippet works perfectly on unrooted devices too :)Dezhnev
M
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();
}
Missis answered 24/5, 2012 at 13:59 Comment(5)
My code is also working fine I just want to know is it create any problem on unrooted device ?Macron
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.Distrain
Thanks @Distrain . I will change it to String outFileName = getDatabasePath() + dbname;Missis
Should this not be myContext.getDatabasePath(dbname)? Also getDatabasePath(dbName) returns a file object not a String.Vondavonni
This seems to result in an export of an encrypted database file (see question - #44397583)Declinate
S
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;
}
Scabies answered 15/3, 2015 at 8:32 Comment(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.Redwood
G
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

Greybeard answered 24/5, 2012 at 13:48 Comment(1)
My code is also working fine I just want to know is it create any problem on unrooted device ?Macron
C
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();
}
Clywd answered 12/2, 2016 at 10:57 Comment(0)
O
0

This works for Kotlin.

assets.open("sqlite_db_in_assets.db")
      .copyTo(getDatabasePath("sqlite_db_in_device.db").outputStream())
Ozonide answered 8/8, 2018 at 5:19 Comment(0)
L
-1

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

Linage answered 13/8, 2019 at 11:40 Comment(6)
This should probably be a comment instead. Why do you think it deserves to be an answer?Tetartohedral
@Tetartohedral Because if correct, it justifies closing the whole question marking it "bad practice". Not sure how it works here...Linage
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.Tetartohedral
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.Linage
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.Tetartohedral
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.Linage

© 2022 - 2024 — McMap. All rights reserved.