安卓:如何在开发中使用预先准备好的数据库

在实际开发中,我们经常遇到需使用自己已经定制好数据的数据库,一般的做法是:

1、用Sqlite数据库工具制作数据库文件,网上有许多这类工具,可以自己搜索下载,我用的是SqliteStudio。

需要注意的是android对其使用的Sqlite数据库有一些固定的要求,包括:

(1)数据库文件中必须有一个名为“android_metadata”的表,这个表只包括一个字段:locale,也只需要一条记录,默认值为“en_US”。

 

CREATE TABLE "android_metadata" ("locale" TEXT DEFAULT 'zh_CN')
INSERT INTO "android_metadata" VALUES ('zh_CN')

(2)数据库文件中的其它表,必须包括一个名字“_id”的关键字字段,ListView等使用的适配器自动绑定'_id'如果没有会报错

2、将制作好的数据库文件放在Android项目的assets文件夹或res/raw文件夹下(我习惯放在assets文件夹下)。

3、Android项目使用的数据库文件一般在/data/data/项目包名/databases/下,使用代码使程序在运行时进行判断,如该路径下没有指定的文件,则进行复制,否则不做任何操作。

4、如数据库文件不超过1M,可以直接复制,否则需要预先将数据库文分割为几个不超过1M的文件,复制到目标路径后再组合一一起。 

实例:

使用一个DBHelper类来实现判断和复制数据库的操作,这个类继承自SQLiteOpenHelper类。

  1 package com.bluehowk.homecooking;
  2 import java.io.File;
  3 import java.io.FileOutputStream;
  4 import java.io.IOException;
  5 import java.io.InputStream;
  6 import java.io.OutputStream;
  7 
  8 import android.content.Context;
  9 import android.database.sqlite.SQLiteDatabase;
 10 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 11 import android.database.sqlite.SQLiteException;
 12 import android.database.sqlite.SQLiteOpenHelper;
 13 
 14 /**
 15 * 用法:
 16 * DBHelper dbHelper = new DBHelper(this);
 17 * dbHelper.createDataBase();
 18 * SQLiteDatabase db = dbHelper.getWritableDatabase();
 19 * Cursor cursor = db.query()
 20 * db.execSQL(sqlString);
 21 * 注意:execSQL不支持带;的多条SQL语句
 22 * 见execSQL的源码注释 (Multiple statements separated by ;s are not supported.)
 23 * 将把assets下的数据库文件直接复制到DB_PATH,但数据库文件大小限制在1M以下
 24 * 如果有超过1M的大文件,则需要先分割为N个小文件,然后使用copyBigDatabase()替换copyDatabase()
 25 */
 26 public class DBHelper extends SQLiteOpenHelper {
 27    //用户数据库文件的版本
 28    private static final int DB_VERSION    = 1;
 29    //数据库文件目标存放路径为系统默认位置,cn.arthur.examples 是你的包名
 30    private static String DB_PATH        = "/data/data/com.bluehowk.homecooking/databases/";
 31 /*
 32    //如果你想把数据库文件存放在SD卡的话
 33    private static String DB_PATH        = android.os.Environment.getExternalStorageDirectory().getAbsolutePath()
 34                                        + "目标路径";
 35 */
 36    //下面两个静态变量分别是目标文件的名称和在assets文件夹下的文件名
 37    private static String DB_NAME         = "cookdata.db";
 38    private static String ASSETS_NAME     = "cookdata.db";
 39 
 40    private SQLiteDatabase myDataBase    = null;
 41    private final Context myContext;
 42 
 43     /** 
 44      * 如果数据库文件较大,使用FileSplit分割为小于1M的小文件
 45      * 此例中分割为 hello.db.101    hello.db.102    hello.db.103
 46      */
 47    //第一个文件名后缀
 48    private static final int ASSETS_SUFFIX_BEGIN    = 101;
 49    //最后一个文件名后缀
 50    private static final int ASSETS_SUFFIX_END        = 103;
 51    
 52    /**
 53     * 在SQLiteOpenHelper的子类当中,必须有该构造函数
 54     * @param context    上下文对象
 55     * @param name        数据库名称
 56     * @param factory    一般都是null
 57     * @param version    当前数据库的版本,值必须是整数并且是递增的状态
 58     */
 59    public DBHelper(Context context, String name, CursorFactory factory, int version) {
 60        //必须通过super调用父类当中的构造函数
 61        super(context, name, null, version);
 62        this.myContext = context;
 63    }
 64    
 65    public DBHelper(Context context, String name, int version){
 66        this(context,name,null,version);
 67    }
 68 
 69    public DBHelper(Context context, String name){
 70        this(context,name,DB_VERSION);
 71    }
 72    
 73    public DBHelper (Context context) {
 74        this(context, DB_PATH + DB_NAME);
 75    }
 76    
 77    public void createDataBase() throws IOException{
 78        boolean dbExist = checkDataBase();
 79        if(dbExist)
 80        {
 81            //数据库已存在,不做任何操作
 82        }
 83        else
 84        {
 85            //创建数据库
 86            try {
 87                File dir = new File(DB_PATH);
 88                if(!dir.exists()){
 89                    dir.mkdirs();
 90                }
 91                File dbf = new File(DB_PATH + DB_NAME);
 92                if(dbf.exists()){
 93                    dbf.delete();
 94                }
 95                SQLiteDatabase.openOrCreateDatabase(dbf, null);
 96                // 复制asseets中的数据库文件到DB_PATH下
 97                copyDataBase();
 98            } catch (IOException e) {
 99                throw new Error("数据库创建失败");
100            }
101        }
102    }
103    
104    //检查数据库是否有效
105    private boolean checkDataBase(){
106        SQLiteDatabase checkDB = null;
107        String myPath = DB_PATH + DB_NAME;
108        try{            
109            checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
110        }catch(SQLiteException e){
111            //database does't exist yet.
112        }
113        if(checkDB != null){
114            checkDB.close();
115        }
116         return checkDB != null ? true : false;
117    }
118 
119    /**
120     * 复制assets文件中的数据库到指定路径
121     * 使用输入输出流进行复制
122    **/
123    private void copyDataBase() throws IOException{
124        
125        InputStream myInput = myContext.getAssets().open(ASSETS_NAME);
126        String outFileName = DB_PATH + DB_NAME;
127        OutputStream myOutput = new FileOutputStream(outFileName);
128        byte[] buffer = new byte[1024];
129        int length;
130        while ((length = myInput.read(buffer))>0){
131            myOutput.write(buffer, 0, length);
132        }
133        myOutput.flush();
134        myOutput.close();
135        myInput.close();
136    }
137    
138    //复制assets下的大数据库文件时用这个
139    private void copyBigDataBase() throws IOException{
140        InputStream myInput;
141        String outFileName = DB_PATH + DB_NAME;
142        OutputStream myOutput = new FileOutputStream(outFileName);
143        for (int i = ASSETS_SUFFIX_BEGIN; i < ASSETS_SUFFIX_END+1; i++) {
144            myInput = myContext.getAssets().open(ASSETS_NAME + "." + i);
145            byte[] buffer = new byte[1024];
146            int length;
147            while ((length = myInput.read(buffer))>0){
148                myOutput.write(buffer, 0, length);
149            }
150            myOutput.flush();
151            myInput.close();
152        }
153        myOutput.close();
154    }
155    
156    @Override
157    public synchronized void close() {
158        if(myDataBase != null){
159            myDataBase.close();
160        }
161        super.close();
162    }
163    
164    
165    @Override
166    public void onCreate(SQLiteDatabase db) 
167    {
168    }
169    
170    /**
171     * 数据库创建时执行,如果不是预制的数据库,可以在这些写一些创建表和添加初始化数据的操作
172     * 如:db.execSQL("create table cookdata (_id integer primary key,cook_name 
173     * varchar(20),cook_sort varchar(20))");
174     */
175    @Override
176    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
177    {
178        /**
179         * 数据库升级时执行,前面我们定义的DB_VERSION就是数据库版本,在版本升高时执行
180         * 一般做一些数据备份和恢复到新数据库的操作。
181         */
182    }
183 }

 

你可能感兴趣的:(安卓:如何在开发中使用预先准备好的数据库)