Question

I was developing android app on eclipse till now and now I'm using Mono for Android.

I am trying to copy the database from Assets folder, copy it onto the SD Card, then read data from it. I'm using the following code for the same. However I'm getting database corruption error.

After running the following code, empty database is getting created on SD card but the actual table is not getting copied.

Also how to check SD card content in MonoDevelop. I'm currently using eclipse for the same.

As I'm just beginner to android development, any help appreciated.

public class DbManager
{
    private Context ctx;
    private SQLiteDatabase mDb;
    private DatabaseHelper dataHelper;
    private String DATABASE_PATH = "/data/data/HelloM4A.HelloM4A/databases/";
    private static String DATABASE_NAME = "CompanyMaster.db";
    private SQLiteCursor cur;
    private String[] b1;
    private int x;
    private static int DATABASE_VERSION = 1;

    public DbManager(Context ctx)
    {
        this.ctx = ctx;
        dataHelper = new DatabaseHelper(ctx);
    }

    private class DatabaseHelper : Android.Database.Sqlite.SQLiteOpenHelper
    {
        public DatabaseHelper AnyName
        { get; set; }
        Context myContext = null;

        public DatabaseHelper(Context context)
            : base(context, DATABASE_NAME, null, DATABASE_VERSION)
        {
            this.myContext = context;
        }

        public override void OnCreate(Android.Database.Sqlite.SQLiteDatabase db)
        {
        }

        public override void OnUpgrade(Android.Database.Sqlite.SQLiteDatabase db, 
                                       int oldVersion, int newVersion)
        {
            OnCreate(db);
        }
    }

    public bool checkDataBase()
    {
        String myPath = DATABASE_PATH + DATABASE_NAME;
        Java.IO.File f = new Java.IO.File(myPath);
        return f.Exists();
    }

    public void createDataBase()
    {
        openDB();
        try
        {
            Stream stream;
            string destPath = Path.Combine(Environment.GetFolderPath(
            Environment.SpecialFolder.Personal), "CompanyMaster.db");

            if (new Java.IO.File(destPath).Exists())
                using (stream = ctx.Assets.Open("CompanyMaster.db"))
                {
                    OutputStream myOutput = new FileOutputStream(DATABASE_PATH +
                                                                 DATABASE_NAME);

                    byte[] buffer = new byte[1024];
                    int length;
                    while ((length = stream.Read(buffer, 0, 1024)) > 0)
                    {
                        myOutput.Write(buffer, 0, length);
                    }

                    if (mDb.IsOpen == true)
                        mDb.Close();
                    myOutput.Flush();
                    myOutput.Close();
                    stream.Close();
                }
        }
        catch (Exception e)
        { }
    }

    public DbManager openDB()
    {
        try
        {
            mDb = dataHelper.WritableDatabase;
        }
        catch (Exception e)
        { }
        return this;
    }

    public String[] getSymbol()
    {
        try
        {
            cur = (SQLiteCursor)mDb.RawQuery("select symbol, company_name " + 
                                             "from Scrip", null);
        }
        catch (SQLiteException e)
        { }
        b1 = new String[2168];
        x = 0;
        if (cur.MoveToFirst())
        {
            do`
            {
                b1[x] = cur.GetString(cur.GetColumnIndex("symbol"));
                x++;
            }
            while (cur.MoveToNext());
        }
        cur.Close();
        return b1;
    }

    public void close()
    {
        mDb.Close();
    }
}

EDIT

After various suggestions, I tried following code :

public void createDataBase()
{
    openDB();

    try    
    {           
        var dataFile = ctx.ApplicationContext
                          .GetDatabasePath(DATABASE_NAME)
                          .AbsolutePath;
        Console.WriteLine("path="+
                          ctx.ApplicationContext
                             .GetDatabasePath(DATABASE_NAME)
                             .AbsolutePath);

        // I get path=/data/data/HelloM4A.HelloM4A/databases/CompanyMaster.db 
        // which is correct.
        if (!System.IO.File.Exists(dataFile))
        {
            using (var input = ctx.Assets.Open(DATABASE_NAME))
            using (var output = System.IO.File.Create(dataFile))
            {
                var buffer = new byte[1024];
                int len;
                while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
                {
                    output.Write(buffer, 0, len);
                }
            }
        }
    }
    catch
    {

    }  
}

public DbManager openDB()
{
    try
    {
        mDb = dataHelper.WritableDatabase;
    }
    catch
    {

    }

    return this;
}

Now the issue is if I don't use openDB() within createDataBase() , it gives fileNotFoundException.

and if I use openDB() within createDataBase(), it created empty DB and hence DB doesn't get copied and I get Blank DB as final ouput because of following condition if (!System.IO.File.Exists(dataFile)).

Since already empty DB is created it doesn't traverse inside if.

What can be done here?

Was it helpful?

Solution

I use this code to copy out of the assets folder to where I want it (you should be able to modify it to suit yourself):

const string dbName = "evolution.sqlite";
var dataDirectory = Path.Combine(ApplicationContext.FilesDir.AbsolutePath,
                                 "databases");
var dataFile = Path.Combine(dataDirectory, dbName);

if (!Directory.Exists(dataDirectory))
{
    Directory.CreateDirectory(dataDirectory);
}

if (!File.Exists(dataFile))
{
    using (var input = ApplicationContext.Assets.Open(dbName))
    using (var output = File.Create(dataFile))
    {
        var buffer = new byte[1024];
        int len;
        while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            output.Write(buffer, 0, len);
        }
    }
}

Note: I dynamically create the path as I am using an ORM instead of the DB helper classes. You could use dataDirectory = context.GetDatabasePath("").AbsolutePath(); instead.

You must do this before you use the DatabaseHelper as the database will also try and create the database. I do this in my Activity.OnCreate(...) method and then use the DatabaseHelper afterwards.

Thus, if my code was in a function called CopyDB(...) you use the method:

public DbManager openDB()
{
    CopyDB(...);

    try
    {
        mDb = dataHelper.WritableDatabase;
    }
    catch(Exception e) 
    {
    }

    return this;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top