Reputation: 340
I am attempting to copy a pre-loaded DB from my assets folder to somewhere I can read from it, however I am getting an IOException when my code tries to call the InputStream to get the DB from the assets folder.
I have been following the tutorials on Reign Design as well as this excellent answer from SO: https://stackoverflow.com/a/9109728/3699923. My question is extremely similar to Error copying SQLite DB from Asset folder, however he was getting a file not found error, and mine is a more generic "error copying file".
I have also tried deleting the app from my device and testing again to ensure that it wasn't related to the new file being already on device.
My DBHelper file (this is an excerpt):
public class AppDataDBHelper extends SQLiteOpenHelper {
private static String TAG = "AppDataDBHelper"; // Tag just for the LogCat window
private static String DB_NAME ="appdata.db";// Database name
private static String DB_PATH = "";
private static String DB_TABLE = "Bonus_Data";
private static int DB_VERSION = 1;
private SQLiteDatabase mDataBase;
private final Context mContext;
public AppDataDBHelper(Context context) {
super(context, DB_NAME, null,DB_VERSION);
this.mContext = context;
DB_PATH = context.getAssets() + "/databases/";
// DB_PATH = context.getApplicationInfo().dataDir + "/databases/";
Log.e(TAG,DB_PATH + DB_NAME);
}
public void createDataBase() throws IOException
{
//If the database does not exist, copy it from the assets.
Log.e(TAG,"Entered createDatabase");
boolean mDataBaseExist = checkDataBase();
if(!mDataBaseExist)
{
this.getReadableDatabase();
this.close();
try
{
//Copy the database from assets
Log.e(TAG,"createDatabase passing to copyDatabase");
copyDataBase();
Log.e(TAG, "createDatabase database created");
}
catch (IOException mIOException)
{
throw new Error("ErrorCopyingDataBase");
}
}
}
//Check that the database exists here: /data/data/your package/databases/Da Name
private boolean checkDataBase()
{
Log.e(TAG,"entered checkDatabase");
File dbFile = new File(DB_PATH + DB_NAME);
//Log.v("dbFile", dbFile + " "+ dbFile.exists());
return dbFile.exists();
}
//Copy the database from assets
private void copyDataBase() throws IOException
{
Log.e(TAG,"entered copyDatabase");
close();
Log.e(TAG,"copyDatabase close");
InputStream mInput = mContext.getAssets().open(DB_NAME);
Log.e(TAG,"copyDatabase inputStream");
String outFileName = DB_PATH + DB_NAME;
Log.e(TAG,DB_PATH + " | " + DB_NAME);
OutputStream mOutput = new FileOutputStream(outFileName);
Log.e(TAG,"copyDatabase outputStream");
FileHelper.copyFile(mInput, mOutput);
getWritableDatabase().close();
}
The call from my relevant activity file:
// Handle the appData DB.
SQLiteDatabase appDB = null;
appDBHelper = new AppDataDBHelper(this);
try {
Log.e(TAG,"Calling createDataBase");
appDBHelper.createDataBase();
} catch (IOException ioe) {
throw new Error("Unable to create database");
}
try {
Log.e(TAG,"Calling openDatabase");
appDBHelper.openDataBase();
} catch(SQLException sqle){
throw sqle;
}
And the error I'm seeing in logcat:
2019-02-02 22:40:29.103 603-603/net.tommyc.android.tourofhonor E/splashScreen: Going to Bonus List
2019-02-02 22:40:29.170 603-603/net.tommyc.android.tourofhonor D/ScrollView: initGoToTop
2019-02-02 22:40:29.195 603-603/net.tommyc.android.tourofhonor E/AppDataDBHelper: android.content.res.AssetManager@9353a47/databases/appdata.db
2019-02-02 22:40:29.195 603-603/net.tommyc.android.tourofhonor E/bonusListing: Calling createDataBase
2019-02-02 22:40:29.195 603-603/net.tommyc.android.tourofhonor E/AppDataDBHelper: Entered createDatabase
2019-02-02 22:40:29.195 603-603/net.tommyc.android.tourofhonor E/AppDataDBHelper: entered checkDatabase
2019-02-02 22:40:29.224 603-603/net.tommyc.android.tourofhonor E/AppDataDBHelper: createDatabase passing to copyDatabase
2019-02-02 22:40:29.224 603-603/net.tommyc.android.tourofhonor E/AppDataDBHelper: entered copyDatabase
2019-02-02 22:40:29.224 603-603/net.tommyc.android.tourofhonor E/AppDataDBHelper: copyDatabase close
2019-02-02 22:40:29.224 603-603/net.tommyc.android.tourofhonor D/AndroidRuntime: Shutting down VM
2019-02-02 22:40:29.225 603-603/net.tommyc.android.tourofhonor E/AndroidRuntime: FATAL EXCEPTION: main
Process: net.tommyc.android.tourofhonor, PID: 603
java.lang.Error: ErrorCopyingDataBase
at net.tommyc.android.tourofhonor.AppDataDBHelper.createDataBase(AppDataDBHelper.java:57)
at net.tommyc.android.tourofhonor.bonusListing.onCreate(bonusListing.java:53)
at android.app.Activity.performCreate(Activity.java:7183)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2908)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3030)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6938)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
Upvotes: 1
Views: 213
Reputation: 634
[update: tested ok codes] I have updated the code from copying database to reading a group of names from database table.
For accessing external sqlite database stored in assets folder, this is working for me so please check it out.
data inserted into external sqlite database but not saving in android studio
For your case, I recommend following changes:
1) my table in sqlite dbbrowser:
CREATE TABLE `Bonus_Data` (
`id` INTEGER NOT NULL,
`name` TEXT NOT NULL,
PRIMARY KEY(`id`)
);
2) in your AppDataDBHelper class:
public class AppDataDBHelper extends SQLiteOpenHelper{
private static String TAG = "AppDataDBHelper"; // Tag just for the LogCat window
private static String DB_NAME = "appdata.db";// Database name
private static String DB_TABLE = "Bonus_Data";
private static int DB_VERSION = 1;
private SQLiteDatabase mDataBase;
private final Context mContext;
public AppDataDBHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
this.mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public void createDataBase() throws IOException {
//If the database does not exist, copy it from the assets.
Log.e(TAG, "Entered createDatabase");
boolean mDataBaseExist = checkDataBase();
if (!mDataBaseExist) {
this.getReadableDatabase();
this.close();
try {
//Copy the database from assets
Log.e(TAG, "createDatabase passing to copyDatabase");
copyDataBase();
Log.e(TAG, "createDatabase database created");
} catch (IOException mIOException) {
throw new Error("ErrorCopyingDataBase");
}
}
}
//Check that the database exists here: /data/data/your package/databases/Da Name
private boolean checkDataBase() {
Log.e(TAG, "entered checkDatabase");
File dbFile = new File(mContext.getDatabasePath(DB_NAME).getPath());
if (dbFile.exists()) return true;
File dbdir = dbFile.getParentFile();
if (!dbdir.exists()) {
dbdir.mkdirs();
}
return false;
}
//Copy the database from assets
private void copyDataBase() throws IOException {
InputStream mInput = null;
OutputStream mOutput = null;
Log.e(TAG, "entered copyDatabase");
Log.e(TAG, "copyDatabase close");
String outFileName = mContext.getDatabasePath(DB_NAME).getPath();
try {
mInput = mContext.getAssets().open(DB_NAME);
mOutput = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024];
int length;
while ((length = mInput.read(buffer)) > 0) {
mOutput.write(buffer, 0, length);
}
mOutput.flush();
mOutput.close();
mInput.close();
} catch (IOException ie) {
throw new Error("Copydatabase() error ");
}
}
public ArrayList<String> readNames() {
boolean distinct = true;
ArrayList<String> mname = new ArrayList<>();
String[] columns = new String[]{"name"};
//Cursor cursor = ourDatabase.query(DATABASE_TABLE, columns, null, null, null, null, null);
//This is used to draw distinct data values from database table
Cursor cursor = mDataBase.query(distinct, DB_TABLE, columns, null, null, null, null, null, null);
int iName = cursor.getColumnIndex("name");
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
mname.add(cursor.getString(iName));
}
cursor.close();
return mname;
}
//this openRead is needed everytime you access this helper class
public void openRead() {
mDataBase = getReadableDatabase(); //mDatabase should always be initialized or else app crashes while accessing TABLE
}
}
2) finally in the onCreate() method of your activity create database as:
public class TestActivity extends AppCompatActivity {
private static final String TAG = "TestActivity";
private ArrayList<String> name = new ArrayList<>();
private TextView textView_name;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
AppDataDBHelper appDBHelper = new AppDataDBHelper(this);
try {
Log.e(TAG, "Calling createDataBase");
appDBHelper.createDataBase();
} catch (IOException ioe) {
throw new Error("Unable to CREATE DATABASE");
} finally {
appDBHelper.close();
}
textView_name = findViewById(R.id.textView_name);
check();
String message = "";
for (int i=0; i<name.size(); i++) {
message = message + name.get(i) + "\n";
}
textView_name.setText(message);
}
private void check() {
try {
AppDataDBHelper appDataDBHelper = new AppDataDBHelper(this);
appDataDBHelper.openRead(); //without this app crashes
name = appDataDBHelper.readNames();
appDataDBHelper.close();
} catch (Exception e) {
throw new Error("error reading");
}
}
}
Upvotes: 2