This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Android backup/restore: how to backup an internal database?
I am developing an app in which there is SQL lite db. I need to give the user the ability to back up the database and restore it again. How can I do that? Sample code?
And in case my user saved the db, and then upgraded the app to a new DB version code, will restore work? How do I go about that?
In the folder "/data/data/'your.app.package'/databases/" you have a .db file that is your database. You can copy that file, save it, and then place it back there again.
One example on how to backup the database to the external storage:
final String inFileName = "/data/data/<your.app.package>/databases/foo.db";
File dbFile = new File(inFileName);
FileInputStream fis = new FileInputStream(dbFile);
String outFileName = Environment.getExternalStorageDirectory()+"/database_copy.db";
// 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);
}
// Close the streams
output.flush();
output.close();
fis.close();
Can you clarify what you mean by "back up"? SQLite doesn't have a specific backup method; you have to read rows from the db and save them somehow. Many developers use XML to do this.
If the user saves the db and you then move to a new DB version code, you have to decide how you'll do the restore. Again, you have to do the work to read the backup and put it back into the database; neither SQLite nor Android does this for you.
The package android.app.backup contains classes for working with the Android Backup Agent, but they implement a general framework. It's up to you to implement the specifics for each file or database you're backing up.
Related
I need a local database for my application.I created one and i encrypted it.(I know the password).Now i want to load this db to my original application.I want to decrypte it before copy. I had a copy code like this this is working for unencrpyted db. How can I translate this for my encrypted db.Thanks
private void copyDataBase() throws IOException {
//Open your local db as the input stream
InputStream myInput = myContext.getAssets().open(DB_NAME);
// Path to the just created empty db
String outFileName = DB_PATH + DB_NAME;
//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();
}
Looking on the wiki on DB Browser for SQLite repo, DB Browser uses SQLCipher as a default encryption extension, so I assume that you have used the default SQLCipher extension. This means that to use that encrypted DB file on Android, you need to use SQLCipher's Android Port.
More examples and documentation can be found in their Android Repo and here.
Update:
This update explains a sample setup for using SQLiteCipher.
Add SQLCipher dependency in your application's build.gradle file:
compile net.zetetic:android-database-sqlcipher:3.5.7#aar
Initialize SQLCipher's native library before performing any db ops by calling:
net.sqlcipher.database.SQLiteDatabase.loadLibs(context)
(optional, recommended) Create an implementation of:
net.sqlcipher.database.SQLiteOpenHelper or, better yet, make your existing SQLiteOpenHelper extend from this class
Then whenever you request a database (getReadableDatabase() or getWriteableDatabase()), supply your encryption password with it, e.g.,
SQLiteDatabase db = helper.getReadableDatabase(_PASSWORD_)
See more details on this gist.
Also, in your case you need to copy the encrypted database from the raw assets folder to the path returned by calling Context.getDatabasePath() for the first time your app is run.
Hope this explains the things to you,
Regards
I create a table in sqlite database I am doing all the CRUD operation but I want to see my database schema . I try through DDMS tool of eclipse IDE but there is no database. How can I see my database.i am using real device. Please Help me.
Thanks in advance
You can use this method:
STEP 1: First export the database by writing function :
public static void backupDatabase() throws IOException {
//Open your local db as the input stream
String inFileName = "/data/data/com.myapp.main/databases/MYDB";
File dbFile = new File(inFileName);
FileInputStream fis = new FileInputStream(dbFile);
String outFileName = Environment.getExternalStorageDirectory()+"/MYDB";
//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);
}
//Close the streams
output.flush();
output.close();
fis.close();
}
Taken from Stack overflow link
Then download DB Browser for SQLite and open database file there.DB Browser for SQLite
And you are good to go.Inform me if you found any difficulties while implementing this.
In a real device you cannot access the SQLite DB unless ur phone is rooted.. in a virtual device however you can access it. but there is no way u can see the actual schema. all you see is some text files and once you open them up your columns(data fields) are separated by tabs or something. so
How can I see my database? YOU CAN'T
Only rooted real device can be access using some jar in eclipse. Other wise you can seed database structure in emulator from DDMS Respective. To know how to do this.
Please red this to solve your problem.
Im doing an app which uses sqlite database There is an feature in my app having a button 'Update Database'.
When user clicks on the 'Update Database' button i need to upgrade the old db file with new db file from URL.
How to do this. the research tells me that we cant change a db as it gets place in an .apk file.
Is there any solution to this.
Please help me out.
Thank you.
private void importDatabase(String inputFileName) throws IOException
{
InputStream mInput = new FileInputStream(inputFileName);
String outFileName = YOUR_DB_PATH_HERE;
OutputStream mOutput = new FileOutputStream(outFileName);
byte[] mBuffer = new byte[1024];
int mLength;
while ((mLength = mInput.read(mBuffer))>0)
{
mOutput.write(mBuffer, 0, mLength);
}
mOutput.flush();
mOutput.close();
mInput.close();
}
EDIT:
You may find it helpfull:
How to use an existing database with an Android application
Simply you could download the db file from URL using Download Manager and copy the file to this path
/data/data/<YOUR PACKAGE NAME>/databases/
It will automatically update.I have used this and is working
At the first launch of your application, you should copy your database into external/internal storage, out of the apk file.
When you need to update (with statements or by replacing the whole db) you can operate in the internal/external memory without problems.
When you update your application (and maybe the new application has a new db inside), at the first launch of the new app, you should replace the db you stored in the internal/external memory.
I have been creating a pay version of my first app.
I would like to copy the existing database to the new payed app.
How is this possible?
EDIT
In the free app I am using a SQLiteOpenHelper. They can use the same database but would like to use the SQLiteOpenHelper again and can't figure out how to get this to use the other database as the apps have different package names (If they use the same dosn't the free database get deleted when the app gets deleted?).
Please comment if you would like additional info (and perhaps what info you need:))
You have a couple of options, you won't get a package with a different name to directly interact with another packages database.
So you could code a Content Provider into the free app, then allow the paid version to collect data from the content provider, then on first run pass all the data across. This is somewhat cumbersome in my opinion - but would mean the user doesn't need an SDcard, you also stay in control of the data, IE if the user has already used the paid version you can ADD the data onto the database rather than replacing the new one with the old free one...
You could save the database to the SDcard from within the free version, and then collect it with the paid version. Depending how much you want to code, you could set up a Broadcast Receiver in the free app, and then sendBroadcast() from the paid version, that way when the free app receives a broadcast it copes its database to the SDcard, then the paid app collects it. The other way would be for the user to click a save button in the free version, backup to the SDcard, then the user clicks a button in the paid version and it receives it - this can be as simple as copying the file and replacing the app's database, or you could import it to the paid app as a different database, process it adding what you need to the main database then discard it.
As a very loose and simple pointer, you can copy the database to the SDcard with something like this, it is very stripped down from a working bit of code, so should be considered untested to a degree - you will need to add a few catch blocks in places to get it working along with the read write permissions for the SDcard in the manifest:
// Get hold of the db:
InputStream myInput = new FileInputStream("/data/data/com.package.name/databases/database-name");
// Set the output folder on the SDcard
File directory = new File("/sdcard/someFolderName");
// Create the folder if it doesn't exist:
if (!directory.exists())
{
directory.mkdirs();
}
// Set the output file stream up:
OutputStream myOutput = new FileOutputStream(directory.getPath()+ "/database-name.backup");
// Transfer bytes from the input file to the output file
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer))>0)
{
myOutput.write(buffer, 0, length);
}
// Close and clear the streams
myOutput.flush();
myOutput.close();
myInput.close();
Retreival is very similar:
// Set location for the db:
OutputStream myOutput = new FileOutputStream("/data/data/com.package.name/databases/database-name");
// Set the folder on the SDcard
File directory = new File("/sdcard/someFolderName");
// Set the input file stream up:
InputStream myInput = new FileInputStream(directory.getPath()+ "/database-name.backup");
// Transfer bytes from the input file to the output file
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer))>0)
{
myOutput.write(buffer, 0, length);
}
// Close and clear the streams
myOutput.flush();
myOutput.close();
myInput.close();
However I would suggest doing some checks first and questioning the user a little:
Check if a file already exists on the SDcard, if so do they want to overwrite it.
Check they want to overwrite the current database with the backup one
You will also need to do some checks like, is the SDcard mounted ect.
Like I say the code above is really just to give you a little hint as to how you could possibly use the SDcard to move the database.
One of my applications downloads a database from a server.
When I install the application onto my phone, it downloads the file correctly and loads the information, no exceptions thrown or anything.
However, when I upload the apk into the Android Market Place and download it onto the phone, the application downloads the database and then crashes, saying that the sqlite handler was not able to open up the database.
Here's the progression of code:
In the SQLiteOpenHelper:
this.FULL_DB_PATH = new String(this.getWritableDatabase().getPath());
this.getWritableDatabase();
// Code for retrieving the database off of the server:
private void copyDataBase(){
InputStream myInput=null;
OutputStream myOutput=null;
try{
// opening connections
URL url = new URL("server_url_here");
URLConnection ucon=url.openConnection();
myInput = ucon.getInputStream();
myOutput = new FileOutputStream(this.FULL_DB_PATH);
// write to the db here
byte[] buffer = new byte[1024*1024];
int length;
while ((length = myInput.read(buffer))>0){
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
}
catch(Exception e)
{
try{
myOutput.flush();
myOutput.close();
myInput.close();
}
catch(Exception es){}
}
}
I don't know why my colleague is saving the db with a mp3 extension but...it works when we're installing the apk ad-hoc.
For:
myOutput = new FileOutputStream(this.FULL_DB_PATH);
I've also tried:
myOutput = this.getApplicationContext().openFileOutput(this.FULL_DB_PATH, Context.MODE_WORLD_READABLE);
But that doesn't work either.
Any help is greatly appreciated!! I've been tearing my hair out for a couple of hours over this and I just want it to end haha.
What you are doing is copying the file into the /data folder in the android file system. On a normal phone with normal permissions this is not allowed for security reasons. You can do this on the emulator and rooted phones because you have been granted permission to write to /data (normally only read).
To get around this you will need to manually add the information to the database using db.insert(String, String, ContentValues) and db.update(String, ContentValues, String, String[])
It would be nice to be able to do what you are trying but for security reasons it's a very good thing you can't.
The Emulator gives you special access that real phones don't. In other words, I suspect you are directly copying the file into the databases directory on the phone? If so, you can't do that on a non-rooted phone. Hopefully someone will chime in and prove me wrong because this is a problem for me too. I'd like to easily download a db file and install it. What I end up having to do as a work-around is create a new database and load the schema and data through queries.
EDIT:
I would like to share a trick with you. It's simple really. Instead of using just db.insert/db.update/ by themselves, scope them into transactions. In fact, I would scope the whole DB Build as a transaction, or at least just individual tables. I've experienced a 10-50x increase in speed of transactions when they're scoped and then committed all at once.
The other two answers are incorrect, I do believe. I have a backup system in my app where backups are copied to the sd-card, and then copied back to the /data/-folder when the backup is restored. While I have no idea why your code wont work, here is my code to copy the database from the sd-card:
final InputStream in = new FileInputStream(from);
final OutputStream out = new FileOutputStream(to);
final byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0){
out.write(buf, 0, len);
}
in.close();
out.close();
Just to closer investigare the error, try to download to the sd-card instead and then use my code to copy it to the data-folder. The "to" object in my code I get like this:
public static final String DATABASE_PATH = "/data/data/"+SomeClass.class.getPackage().getName()+"/databases/"+ DATABASE_NAME;
final File to = new File(Constant.DATABASE_PATH);