SQLite问题“无法打开数据库文件”

时间:2011-09-06 23:54:42

标签: c# ipad sqlite xamarin.ios

经过大量时间谷歌搜索并在StackOverflow上阅读关于SQLite的其他讨论后,我来找你,但我肯定找不到任何解释我的问题,所以这里是:

  • 上下文:
    我正在开发一个iPad应用程序,它必须在几个时间内处理一些“大量”的数据。在其中一个中,我必须将.kml文件(Google的地理数据的xml)中的点坐标导入到我的数据库中,以便稍后使用MKMapView重用它们并加载它们比在需要显示特定时解析xml更快层

  • 详细信息:
    导入的东西很简单:处理这些文件时,我只关心2个表:

    • 其中一个包含区域定义和详细信息:目前,integer为ID,text用于命名。
    • 一个包含两个real用于坐标存储,一个integer引用第一个表以了解哪个区域点是其中一部分。
      所以只要读取我的文件,我首先为新区域创建一个条目,然后我将点插入到第二个表中,在第一个表中创建最后一个区域的ID ......没什么复杂的!

    但......

  • 问题:
    运行一段时间之后,我从SQLite得到一个例外,其中有着名的消息“无法打开数据库文件”,然后它就来了,我无法对数据库做更多的事情。此异常可以在区域创建或点插入方法中随机发生。

  • 我的反思:
    考虑到这些文件中的众多点,我怀疑内存或磁盘饱和,但我的应用程序的其他部分丢弃了这些点(在我看来)。
    首先,内存:当异常发生时,应用程序使用大约10或12 MB的RAM。它看起来非常庞大,但这是由于内存中加载了~10MB .kml文件,所以可以解释。最重要的是,我的应用程序中的MKMapView处理了地图上方的大量高分辨率图块层,因此导致内存峰值可以承受20甚至25MB而不会使iPad崩溃。
    第二,磁盘:当重置我的数据库并仅填充上述2个表时,发生异常时的db文件大小总是大约2.2或2.5MB,但是当我填写其他表时(我的应用程序的其他部分运行良好!) db文件大约是6或7MB,设备根本不会抱怨。

  • 那又怎样?!
    CPU愤怒和恐慌?我不这么认为,因为我的数据库中的其他一些表格在同一个节奏中被填充而没有问题...并且在模拟器中运行我的应用程序崩溃,核心i7只是嘲笑工作。
    SQLite使用不好?我们去!在我看来,这是唯一的解决方案!但我真的无法理解这里发生了什么,因为我处理我的请求的方式与我在其他应用程序中的处理方式相同 - 重复自己 - 工作就像一个魅力!

  • SQLite详细信息:
    我有一个DB类,它是一个单例我用来避免每次请求创建/释放SqliteConnection对象,我所有处理数据库的方法都包含在这个类中,以确保我不会在不知情的情况下在任何其他地方玩连接。以下是本课程的相关方法:

    public void     saveZone(ObjZone zone)  { //at this point, just creates an entry with a name and let sqlite give it a new id
        lock (connection) { //SqliteConnection object
            try {
                openConnection();
                SqliteCommand cmd = connection.CreateCommand();
                cmd.CommandText = zone.id == 0 ?
                    "insert into ZONES (Z_NAME) values (" + format(zone.name) + ") ;" :
                    "update ZONES set Z_NAME = " + format(zone.name) + " where Z_ID = " + format(zone.id) + " ;";
                cmd.ExecuteNonQuery();
                if (zone.id == 0) {
                    cmd.CommandText = "select Z_ID from ZONES where ROWID = last_insert_rowid() ;";
                    zone.id = uint.Parse(cmd.ExecuteScalar().ToString());
                }
                cmd.Dispose();
            }
            catch (Exception e) {
                Log.failure("DB.saveZone(" + zone.ToString() + ") : [" + e.GetType().ToString() + "] - " +
                    e.Message + "\n" + e.StackTrace); //custom Console.WriteLine() method with some formating
                throw e;
            }
            finally {
                connection.Close();
            }
        }
    }
    
    public void     setPointsForZone(List<CLLocationCoordinate2D> points, uint zone_id) { //registers points for a given zone
        lock (connection) {
            try {
                openConnection();
                SqliteCommand cmd = connection.CreateCommand();
                cmd.CommandText = "delete from ZONESPOINTS where Z_ID = " + format(zone_id);
                cmd.ExecuteNonQuery();
                foreach(CLLocationCoordinate2D point in points) {
                    cmd.CommandText = "insert into ZONESPOINTS values " +
                        "(" + format(zi_id) + ", " + format(point.Latitude.ToString().Replace(",", ".")) + ", "
                        + format(point.Longitude.ToString().Replace(",", ".")) + ");";
                    cmd.ExecuteNonQuery();
                    cmd.Dispose();
                }
            }
            catch (Exception e) {
                Log.failure("DB.setPointsForZone(" + zone_id + ") : [" + e.GetType().ToString() + "] - " + e.Message);  
                throw e;
            }
            finally {
                connection.Close();
            }
        }
    }
    

    为了尽可能清楚,以下是上面两个中引用的一些方法(我使用这个自定义openConnection()方法,因为我在大多数表中使用外键约束而级联行为不是默认启用,但我需要它们。):

    void openConnection() {
        try {
            connection.Open();
            SqliteCommand cmd = connection.CreateCommand();
            cmd.CommandText = "PRAGMA foreign_keys = ON";
            cmd.ExecuteNonQuery();
            cmd.Dispose();
        }
        catch (Exception e) {
            Log.failure("DB.openConnection() : [" + e.GetType().ToString() + "] - " + e.Message);
            throw e;
        }
    }
    
    public static string format(object o) {
        return "'" + o.ToString().Replace("'", "''") + "'";
    }
    

,对小说感到抱歉,我可能已经感谢你阅读了所有这些内容,不是吗?!无论如何,如果我错过了一些有用的东西,请告诉我,我会尽快记录下来。 我希望有人能够帮助我,无论如何,提前谢谢你! (我为我可怜的疯狂英语道歉。)

修改
我的问题是“解决了”!经过一些调试pourposes的更改,没有大的修改,也没有成功,我把代码放回到我发布的状态......现在它可以工作了。但是如果有人能给我解释可能发生的事情,我真的很感激!似乎SQLite行为(至少在iPad上 - 从未在其他任何地方使用过它)在某些时候可能非常模糊......:/

1 个答案:

答案 0 :(得分:2)

我不会为此而交叉,但我会尝试两件事:

  1. 如果可能,将KML文件预处理到第二个SQLite数据库,并使用此数据库导入主数据库中的数据(考虑较低的内存/处理器要求)
  2. 小批量交易导入的数据。
  3. HTH

    编辑:您可能已经检查了这一点,但无论如何:unable to open database