复制数据库monodroid时出现数据库损坏错误

时间:2012-02-17 09:50:15

标签: c# android database eclipse xamarin.android

我在eclipse上开发Android应用程序到现在为止,现在我正在使用Mono for Android

我正在尝试从Assets文件夹中复制数据库,将其复制到SD卡上,然后从中读取数据。我正在使用以下代码。但是我收到数据库损坏错误

运行以下代码后,SD卡上将创建空数据库,但实际表格未被复制。

如何检查MonoDevelop中的SD卡内容。我目前正在使用eclipse。

因为我刚刚开始进行Android开发,所以有任何帮助。

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();
    }
}

修改

经过各种建议,我尝试了以下代码:

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;
}

现在的问题是,如果我在openDB()中未使用createDataBase(),则会fileNotFoundException

如果我在openDB()中使用createDataBase(),它会创建空数据库,因此DB不会被复制,因为条件if (!System.IO.File.Exists(dataFile)),我将获得空白数据库作为最终输出。< / p>

由于已经创建了空DB,因此它不会遍历内部。

这里可以做些什么?

1 个答案:

答案 0 :(得分:1)

我使用此代码将assets文件夹复制到我想要的位置(您应该能够修改它以适合自己):

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);
        }
    }
}

注意:我动态创建路径,因为我使用的是ORM而不是DB帮助程序类。 您可以改为使用dataDirectory = context.GetDatabasePath("").AbsolutePath();

您必须在使用DatabaseHelper之前执行此操作,因为数据库也将尝试创建数据库。我在Activity.OnCreate(...)方法中执行此操作,然后使用DatabaseHelper

因此,如果我的代码位于名为CopyDB(...)的函数中,则使用以下方法:

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

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

    return this;
}