【问题标题】:android, how to exec a sql file in sqlitedatabaseandroid,如何在 sqlitedatabase 中执行 sql 文件
【发布时间】:2012-01-02 04:53:32
【问题描述】:

我将“food_db.sql”文件存储在 /res/raw 文件夹中, 它有大量的“插入”。

我的问题是如何在我的 android 应用程序中执行文件并将数据导入 sqlite 数据库?

这是我的数据库代码。有什么建议吗?

private static class DbHelper extends SQLiteOpenHelper{

    public DbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        // TODO Auto-generated constructor stub
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" +
                KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
                KEY_NAME + " TEXT NOT NULL, " + 
                KEY_HOTNESS + " TEXT NOT NULL);");
                    // how do i exec the sql file and get the data into this DB table?
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // TODO Auto-generated method stub
        db.execSQL("DROP TABLE IF EXISTS" + DATABASE_TABLE);
        db.execSQL("DROP TABLE IF EXISTS" + RECORD_TABLE);
        onCreate(db);
    }

}

【问题讨论】:

    标签: android sql database sqlite


    【解决方案1】:

    我专门为你写了这篇

    我使用了与您相同的文件名"/raw/food_db.sql",但那导致错误我不得不将其命名为"/raw/ food_db”。我猜是因为您没有在代码中使用文件名,而是像“R.raw.food_db”这样写的 ResourceIds 并且点会混淆系统。

    在你的 DbSource 中有一个方法...假设某处有这样的代码:

    private SQLiteDatabase db;
    ...
    DbHelper dbHelper = new DbHelper(context);
    this.db = dbHelper.getWritableDatabase();
    

    你把这个方法放在那里:

    /**
     * This reads a file from the given Resource-Id and calls every line of it as a SQL-Statement
     * 
     * @param context
     *  
     * @param resourceId
     *  e.g. R.raw.food_db
     * 
     * @return Number of SQL-Statements run
     * @throws IOException
     */
    public int insertFromFile(Context context, int resourceId) throws IOException {
        // Reseting Counter
        int result = 0;
    
        // Open the resource
        InputStream insertsStream = context.getResources().openRawResource(resourceId);
        BufferedReader insertReader = new BufferedReader(new InputStreamReader(insertsStream));
    
        // Iterate through lines (assuming each insert has its own line and theres no other stuff)
        while (insertReader.ready()) {
            String insertStmt = insertReader.readLine();
            db.execSQL(insertStmt);
            result++;
        }
        insertReader.close();
    
        // returning number of inserted rows
        return result;
    }
    

    这样调用它(我从一个 Activity 中尝试过,以便 Toast 可以输出消息)。仔细看,错误也是“Toasted”。

    try {
            int insertCount = database.insertFromFile(this, R.raw.food_db);
            Toast.makeText(this, "Rows loaded from file= " + insertCount, Toast.LENGTH_SHORT).show();
        } catch (IOException e) {
            Toast.makeText(this, e.toString(), Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    

    享受吧!

    哦..顺便说一句:此代码适用于每个插入语句都有自己的行的文件。

    【讨论】:

    • 谢谢你的答案……只是另一个简单的问题,。如何在我的应用程序的起点获取此 sql 文件 exec?我的意思是,一旦我启动应用程序,文件数据将存储到创建的数据库中。再次感谢您的帮助...
    • 您可能应该在 DbHelper 中的 onUpgrade() 上调用此方法,然后在第一次启动时执行...您不必每次应用程序启动时都这样做,数据库不会被重置每次。如果您稍后升级您的应用程序,您将设置另一个 DB-Version 并最终提供另一个文件,然后将其插入现有数据库之上(就像您在该方法中实现它的方式一样)。看看这方面的教程。 (我只是为了调试目的添加了祝酒词......该方法根本不应该从活动开始)
    • “我特别为你写了这个
    【解决方案2】:
    @Override
    public void onCreate(SQLiteDatabase db) {
        InputStream is = null;
        try {
            is = context.getResources().openRawResource(R.raw.database_init);
            String initSql = IOUtils.toString(is);
            db.execSQL(initSql);
        } catch (IOException e) {
            Log.e(TAG, "Error loading init SQL from raw", e);
        } catch (SQLException e) {
            Log.e(TAG, "Error executing init SQL", e);
        } finally {
            IOUtils.closeQuietly(is);
        }
    }
    

    一个重要的标注是,SQLiteDatabase.execSQL(String sql) 只执行一条 SQL 语句,不支持用分号分隔的多条语句。

    我努力找出为什么我的 database_init.sql 没有按预期工作。

    【讨论】:

    【解决方案3】:

    在一个字符串中插入所有行:

    public int insertFromFile(Context context, int resourceId) throws IOException {
        // Reseting Counter
        int result = 0;
    
    // Open the resource
    InputStream insertsStream = context.getResources().openRawResource(resourceId);
    BufferedReader insertReader = new BufferedReader(new InputStreamReader(insertsStream));
    
    // Iterate through lines (assuming each insert has its own line and theres no other stuff)
    String insertStmt = "";
    while (insertReader.ready()) {
        insertStmt += insertReader.readLine();
        result++;
    }
    insertReader.close();
    
    db.execSQL(insertStmt);
    
    // returning number of inserted rows
    return result;
    }
    

    【讨论】:

    • 考虑解释这将如何解决 OP 的问题。
    • 返回文件的行数,不一定是插入数据库的行数。
    【解决方案4】:

    最好的方法是解析sql文件,将文件拆分成语句列表。

    这并不难,因为我们只需要处理commit,string和escape,但是在短时间内写一个并不容易。

    我找到了一种简单的存档方法,方法是使用来自 SugarORM 源​​代码的正则表达式替换注释字符串 (https://github.com/chennaione/sugar/blob/master/library/src/main/java/com/orm/util/MigrationFileParser.java)

    public MigrationFileParser(String content){
        this.content = content.replaceAll("(\\/\\*([\\s\\S]*?)\\*\\/)|(--(.)*)|(\n)","");
    }
    
    public String[] getStatements(){
        return this.content.split(";");
    }
    

    这种方式有局限性(不能在sql字符串中使用“/*”、“--”),但大多数情况下都可以。

    希望有帮助

    【讨论】:

      猜你喜欢
      • 2015-08-12
      • 2019-04-27
      • 2019-06-23
      • 2011-01-05
      • 1970-01-01
      • 1970-01-01
      • 2011-05-12
      • 2016-11-18
      • 1970-01-01
      相关资源
      最近更新 更多