SQLiteException when copying/decompressing a zipped DB onto Android - android

Currently, I am copying a database from my assets folder to the to the /data/data/package folder. This is that code (from the answer here), which works:
public void copyDataBase() throws IOException{
// open db as input stream
InputStream myInput;
//open empty db as output stream
OutputStream myOutPut;
try {
myInput = myContext.getAssets().open(DB_NAME);
//path to newly created db
String outFileName =DB_PATH + DB_NAME;
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);
}
myOutPut.flush();
myOutPut.close();
myInput.close();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Now in order to save space in the .apk download, I am trying to zip the file before copying it to the /data/data/package folder.
private void copyDataBaseFromZipFile() {
InputStream inputStream = null;
OutputStream outputStream = null;
String sourcePathname = this.getBundledPathname();
String destinationPath = this.getDatabasePathname();
try {
inputStream = this.mContext.getAssets().open(sourcePathname);
ZipInputStream zipStream = new ZipInputStream(inputStream);
int BUFFER = 8096;
outputStream = new FileOutputStream(destinationPath);
BufferedOutputStream dest = new BufferedOutputStream(outputStream, BUFFER);
ZipEntry entry;
while ((entry = zipStream.getNextEntry()) != null) {
if (entry.getName().equals("androidDB.sql")) }
int count;
byte data[] = new byte[BUFFER];
while ((count = zipStream.read(data, 0, BUFFER)) != -1) {
dest.write(data, 0, count);
}
}
}
outputStream.flush();
outputStream.close();
dest.flush();
dest.close();
zipStream.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
When I attempt to open the database later (with SQLiteDatabse), I get this error: android.database.sqlite.SQLiteException: unable to open database file
I haven't changed anything except the file I'm copy from, which is only a zipped version of the one I was previously copying over. The final database is the right size, so it doesn't seem to be still compressed... If anyone has any suggestions or possible reasons WHY it won't open, it would be greatly appreciated.

You should remove these lines:
outputStream.flush();
outputStream.close();
Your BufferedOutputStream probably has some buffered bytes, but since you close outputStream before you call dest.flush(), those bytes are never actually written to the file.

Related

Store db file in android app

I've implemented a parser that parses web-site and then i get a big object that consists of a lot of other objects and arrays and etc. What i want is i need to store all this data to SQLite database, then export the .db file.
Then i want to create an app which will work with that db file. How can i implement it in android?
can i store this db-file to assets and then replace the real db file of the app with this db-file that i get from assets?
Of course i can use json or xml or whatever, but it will take a lot of time to unwrap this data for the final user of the application.
So the idea is to generate the db-file once and then store in the assets.
So i've ended up with a solution. Here is a method to get the sqlite db file from your project
public void backupDB(){
// getDatabasePath
final String inFileName = "/data/data/com.example.yourproject/databases/books-db";
File dbFile = new File(inFileName);
try {
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();
} catch (FileNotFoundException fileNotFoundException){
Log.e(LOG_TAG,"fileNotFoundException");
fileNotFoundException.printStackTrace();
}catch (IOException ioException){
Log.e(LOG_TAG,"ioException");
ioException.printStackTrace();
}
}
here is method to get it from assets to replace the db of other project, where you want to use this database instead of other.
private void copyAssets() {
AssetManager assetManager = mContext.getAssets();
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open("database_copy.db");
String currentDBPath = "/data/data/com.example.somepackagename/databases/books-db";
out = new FileOutputStream(currentDBPath);
copyFile(in, out);
in.close();
out.flush();
out.close();
} catch(IOException e) {
Log.e("tag", "Failed to copy asset file " , e);
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
}
}

How to copy another database apps to SDCard

I've install an application to my device. But i want to copy that database to SDcard to be used by my apps. I used this code to copy database. But it's failed. And need "su" command
public void copydatabase() throws IOException{
String [] cmd1 = { "su", "cp", "/data/data/com.apps/databases/data01.db", "/mnt/extSdCard/data01.db"};
Process process = new ProcessBuilder(cmd1).start();
try {
process.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Any some code to copy that to SDCard without "su" command??
public static void copyDataBase(Context mActivity) throws IOException {
InputStream myInput = new FileInputStream(
new File("/data/data/" + mActivity.getPackageName()
+ "/databases/" + "xyz.sqlite"));
File files = new File("/sdcard/files/");
files.mkdirs();
String outFileName = "/sdcard/files/xyz.sqlite";
OutputStream myOutput = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024];
int bufferLength;
while ((bufferLength = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, bufferLength);
}
myOutput.flush();
myOutput.close();
myInput.close();
}
I hope its useful to you...

Android - Copying Database from Assets

Here is the code I am using (found in many answers):
InputStream myInput;
try {
myInput = iNezamApplication.getAppContext().getAssets().open(DB_NAME);
String outFileName = DB_PATH + DB_NAME;
OutputStream myOutput = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer))>0){
myOutput.write(buffer, 0, length);
}
myOutput.flush();
myOutput.close();
myInput.close();
} catch (IOException e1) {
e1.printStackTrace();
}
However, I always get an exception after reaching the OutpoutStream line:
java.io.FileNotFoundException: /data/data/package_name/databases/databasename.db: open failed: ENOENT (No such file or directory)
I tried something like this..
final String[] sample_dbName = {"DrugsNew.db"};
int assetDbSize = sample_dbName.length;
File databaseFile = new File( "/data/data/com.handyrep2.ui/databases");
// check if databases folder exists, if not create one and its subfolders
if (!databaseFile.exists()){
databaseFile.mkdir();
}
for(int i=0;i<assetDbSize;i++){
String outFilename =null;
outFilename = "/data/data/com.handyrep2.ui/databases"+ "/" + sample_dbName[i];
File sampleFile = new File(outFilename);
try {
InputStream in = activity.getAssets().open("offlinedb/"+sample_dbName[i]);
OutputStream out = new FileOutputStream(outFilename);
// Transfer bytes from the sample input file to the sample output file
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.flush();
// Close the streams
out.close();
in.close();
}catch(IOException e) {
}
}
Is "package_name" a substitute for your real package name just to post it here or do really use this in your DB_PATH? :)
you must create a File object at first

How to read preexisting database into Android using ORMLite

I want to use preexisting database file using ORMLite in android. I have database.db file of already creted database. I want to use it in my app.
My class extends OrmLiteSqliteOpenHelper.
Can any one have an idea? Please help
I use to copy database file into data path using
public static void copyDataBase(String path,Context c) throws IOException{
//Open your local db as the input stream
InputStream myInput = c.getAssets().open("Mydb.db");
// Path to the just created empty db
String outFileName = "/data/data/packageName/databases/databaseName";
String outFileName2 = "/data/data/packageName/databases/";
File file = new File(outFileName2);
if(!file.exists())
file.mkdirs();
//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();
}
But it wont help me .
This is kind of a stab in the dark since I do not know what your exact problem is, but can't you just specify the database file (and path) in the OrmLiteSqliteOpenHelper constructor?
OrmLiteSqliteOpenHelper(android.content.Context context, String databaseName, android.database.sqlite.SQLiteDatabase.CursorFactory factory, int databaseVersion)
Also there are a number of questions on this forum that deal with opening custom database files. This question is not ORMLite specific but they might get you forward since it open a custom database file.
Hope this help you a bit on your way.
I have solved the problem by below implementation
try {
String destPath = "/data/data/" + context.getPackageName()
+ "/databases";
Log.v("LOG", destPath);
File f = new File(destPath);
if (!f.exists()) {
f.mkdirs();
File outputFile = new File("/data/data/"
+ context.getPackageName() + "/databases",
"Name ofyour Database");
outputFile.createNewFile();
String DatabaseFile = "database file name from asset folder";
InputStream in = context.getAssets().open(DatabaseFile);
OutputStream out = new FileOutputStream(outputFile);
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
in.close();
out.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
Log.v("TAG", "ioexeption");
e.printStackTrace();
}

Copy Database from assets folder in unrooted device

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();
}
}
}
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();
}
/**
* 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;
}
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
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();
}
This works for Kotlin.
assets.open("sqlite_db_in_assets.db")
.copyTo(getDatabasePath("sqlite_db_in_device.db").outputStream())
While technically feasible, I don't believe copying (either to or from) potentially live database file is a good idea.

Categories

Resources