Copying database form assets fails on emulator - android

I used this tutorial to include a database file to my android app. It works fine on my HTC Decire HD. I wanted to run it on emulator to see if tablet layouts look well. Unfortunately the app fails with an error.
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){ <------ HERE, at first iteration
myOutput.write(buffer, 0, length);
}
//Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
}
The message for this error is just 'null', nothing more. Can this be fixed?

private void copyfromAsset()
{
try {
String FILE_TO_READ="data.txt"; //file in asset folder
String TEMP_FILE_NAME="temp.txt"; //or whatever file name you want to give
byte[] buffer = new byte[1024];
int len1 = 0;
InputStream istr=(con.getAssets().open(FILE_TO_READ));
FileOutputStream fos=openFileOutput(TEMP_FILE_NAME,MODE_WORLD_READABLE);
while ((len1 = istr.read(buffer)) !=-1) {
fos.write(buffer, 0, len1); // Write In FileOutputStream.
}
fos.flush();
fos.close();
istr.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
try this method it is working fine for me....hit accept if you found usefull..

public void createDataBase() throws IOException {
boolean dbExist = checkDataBase();
if (dbExist) {
// do nothing - database already exist
}
else {
// By calling this method and empty database will be created into
// the default system path
// of your application so we are going to be able to overwrite that
// database with our database.
try {
copyDataBase();
}
catch (IOException e) {
throw new Error("Error copying database");
}
}
}
/**
* Check if the database already exist to avoid re-copying the file each
* time you open the application.
*
* #return true if it exists, false if it doesn't
*/
private boolean checkDataBase() {
File dbFile = new File(DB_PATH + DB_NAME);
return dbFile.exists();
}
/**
* 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 transferring byte-stream.
*/
private void copyDataBase() throws IOException {
// Open your local DB as the input stream
InputStream myInput = mContext.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 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 the streams
myOutput.flush();
myOutput.close();
myInput.close();
}

Related

How to fetch already created .db and use it on Android Studio?

I've a HOSPITALS.db file in my assets folder. I want to access the data from the DB. I already have a code for accessing the data inside the table, I want to access the .db file itself so it won't produce an error not finding the table.
protected void openDatabase() {
db = openOrCreateDatabase("HOSPITALS", Context.MODE_PRIVATE, null);
}
Get Your Database path using the following
ContextWrapper cw =new ContextWrapper(getApplicationContext());
DB_PATH =cw.getFilesDir().getAbsolutePath()+ "/databases/"; //edited to databases
Then you can go this way
private void copyDataBase()
{
Log.i("Database",
"New database is being copied to device!");
byte[] buffer = new byte[1024];
OutputStream myOutput = null;
int length;
// Open your local db as the input stream
InputStream myInput = null;
try
{
myInput =myContext.getAssets().open(DB_NAME);
// transfer bytes from the inputfile to the
// outputfile
myOutput =new FileOutputStream(DB_PATH+ DB_NAME);
while((length = myInput.read(buffer)) > 0)
{
myOutput.write(buffer, 0, length);
}
myOutput.close();
myOutput.flush();
myInput.close();
Log.i("Database",
"New database has been copied to device!");
}
catch(IOException e)
{
e.printStackTrace();
}
}

Opening a database from external storage Android

I was previously storing a sqlite database in my apps assets folder but have now moved the database to external storage.
My previous copyDatabase() method looked like this.
private void copyDataBase() throws IOException {
InputStream myInput = myContext.getAssets().open(DATABASE_NAME);
OutputStream myOutput = new FileOutputStream(DB_PATH);
byte[] buffer = new byte[AccessibilityNodeInfoCompat.ACTION_NEXT_HTML_ELEMENT];
while (true) {
int length = myInput.read(buffer);
if (length > 0) {
myOutput.write(buffer, 0, length);
} else {
myOutput.flush();
myOutput.close();
myInput.close();
return;
}
}
}
The issue is I'm unsure how to create an InputStream for opening the database from external storage. I can't seem to find the external storage equivalent to myContext.getAssets().open(DATABASE_NAME);
The current database path:
DB_PATH = Environment.getExternalStorageDirectory().getPath().toString()+"/SoulInfoDatabase/BB2SoulDatabase.db";
Step 1: Give storage permission in your App Manifesto file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Step 2: Copy database to your custom SD card Path
private void copyDataBase() throws IOException {
// Open your local db as the input stream
InputStream myInput = context.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
new File(outFileName).createNewFile();
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();
}
Step 3: Then Open your database:
try {
db = SQLiteDatabase.openDatabase(DB_PATH + "/" + DB_NAME, null,
SQLiteDatabase.OPEN_READWRITE
| SQLiteDatabase.NO_LOCALIZED_COLLATORS);
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
WHERE
String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/SoulInfoDatabase";
File file = new File(filePath);
if(!file.exists()){
file.mkdirs();
}
DB_PATH = filePath;
DB_NAME = "BB2SoulDatabase.sqlite";

Loading database from asset folder - Fileoutputstream fails

My problem is that my application always fails when the database is copied from asset folder to the phone path:
/data/data/at.atn.android/databases/
MY databasename:
atnRoutenplaner.sqlite3
My code for the transfer:
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;
File sampleFile = new File(outFileName);
//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();
}
try this,
public void CopyDataBaseFromAsset() throws IOException{
InputStream in = ctx.getAssets().open("mycontacts");
Log.e("sample", "Starting copying" );
String outputFileName = DATABASE_PATH+DATABASE_NAME;
File databaseFile = new File( "/data/data/com.copy.copydatabasefromasset/databases");
// check if databases folder exists, if not create one and its subfolders
if (!databaseFile.exists()){
databaseFile.mkdir();
}
OutputStream out = new FileOutputStream(outputFileName);
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer))>0){
out.write(buffer,0,length);
}
Log.e("sample", "Completed" );
out.flush();
out.close();
in.close();
}

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.

SQLiteException when copying/decompressing a zipped DB onto 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.

Categories

Resources