在Android开发中,需要添加附带的db数据库,用于实现某些需求。例如,选择城市的功能,需要添加city.db。

使用SQLite Database Browser,这款可视化工具来操作db文件。

SQLite DataBase Browser打开city.db,如下图所示:

android 读写file Android 读写db文件_数据库

本篇介绍查找城市

1. 添加city.db文件:

通过是将db文件放置到raw文件夹下,因此,在/res/raw文件夹下放置city.db文件。

android 读写file Android 读写db文件_数据库_02

2. 将外部db文件信息拷贝到运用程序的数据库中:

数据库本质上是指定路径下一个db文件。

数据库的路径:

存放在/data/data/<package name>/databases/目录下。

拷贝一个文件信息到另外一个文件中,可以用文件流来实现。创建一个文件流的操作类:

public class WriterDBUtils {
    //这里的信息字段和外部db文件中信息保持一致。
    public static final String CITYDB_NAME = "city.db";
    //表名
    public static final String TABLE_PROVICE = "m_province";
    public static final String TABLE_CITY = "m_city";
    //字段名
    public static final String COLUMN_PID = "pid";
    public static  final String COLUMN_CNAME = "cname";
    public static final String COLUMN_PNAME = "pname";
    /**
     *利用文件流进行拷贝
     */
     public static void copyDBFromRaw(Context context) {
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            StringBuffer stringBuffer = new StringBuffer();
            stringBuffer.append("/data/data/");
            stringBuffer.append(context.getPackageName());
            stringBuffer.append("/databases");
            File dir=new File(stringBuffer.toString());
            if(!dir.exists()){//防止databases文件夹不存在,不然,会报ENOENT (No such file or directory)的异常
                dir.mkdirs();
            }
            stringBuffer.append("/");
            stringBuffer.append(CITYDB_NAME);
            File file = new File(stringBuffer.toString());
            if (file == null || !file.exists()) {//数据库不存在,则进行拷贝数据库的操作。
                inputStream = context.getResources().openRawResource(R.raw.city);
                outputStream = new FileOutputStream(file.getAbsolutePath());
                byte[] b = new byte[1024];
                int length;
                while ((length = inputStream.read(b)) > 0) {
                    outputStream.write(b, 0, length);
                }
                //写完后刷新
                outputStream.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {//关闭流,释放资源
                    inputStream.close();
                }
                if(outputStream!=null){
                    outputStream.close();
                }
            } catch (Exception e) {
                    e.printStackTrace();
            }

        }
    }
}

文件流是耗时任务,不能在UI线程中执行,可以考虑后台服务中IntentService来执行。IntentService自带异步线程,执行完后自动关闭服务。

public class WriteCityDBIntentService extends IntentService {
    public static final String TAG=WriteCityDBIntentService.class.getSimpleName();
    public WriteCityDBIntentService() {
        super(TAG);
    }
    /**
     *  异步执行,不在主线程执行,执行完后自动停止Service。
     * @param intent
     */
    @Override
    protected void onHandleIntent(Intent intent) {
        WriterDBUtils.copyDBFromRaw(BaseApplication.getAppContext());
    }
}

别忘记,Service是四大组件之一,需要注册。

<service android:name=".service.WriteCityDBIntentService"></service>

备注下异常

ENOENT (No such file or directory)的异常

 解决方式:

 1. 没有给读写权限
 2. 路径不对,少了"/",路径下少了那个文件夹(没有创建)。

3. 根据数据库中数据,实现选择城市功能:

采用DAO设计模式,操作数据库。RxJava执行数据库操作,RxAndroid上更新UI。

这里,列举查询省份的操作:
查询省份的SQL:

public class ProvinceDao implements DAO<Province> {
    @Override
    public List<Province> queryAll() {
        SQLiteDatabase database = null;
        Cursor cursor = null;
        List<Province> list = null;
        try {
            database = context.openOrCreateDatabase(WriterDBUtils.CITYDB_NAME, Context.MODE_PRIVATE, null);
            if (database != null) {
                cursor = database.query(WriterDBUtils.TABLE_PROVICE, new String[]{WriterDBUtils.COLUMN_PID,WriterDBUtils. COLUMN_PNAME}, null, null, null, null, null);
                if (cursor != null && cursor.moveToFirst()) {
                    list = new ArrayList<>();
                    do {
                        list.add(ValuesTransform.transformProvince(cursor));
                    } while (cursor.moveToNext());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {//释放资源
            if (cursor != null) {
                cursor.close();
            }
            if (database != null) {
                database.close();
            }
        }
        return list;
    }
}

RxJava异步执行,RxAndroid更新UI:

/**
     * 查询省份信息
     */
    public void queryProvince(){
       Subscription subscription= Observable.create(new Observable.OnSubscribe<List<Province>>() {
            @Override
            public void call(Subscriber<? super List<Province>> subscriber) {
                //执行查询操作
                List<Province> list= provinceDAO.queryAll();
                subscriber.onNext(list);
            }
        }).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())//订阅者执行的线程,UI线程
                .subscribe(new Action1<List<Province>>() {
            @Override
            public void call(List<Province> provinces) {
                //更新UI
                provinceAdapter.addData(provinces);
            }
        });
        this.compositeSubscription.add(subscription);
    }

4. 项目效果展示:

android 读写file Android 读写db文件_android 读写file_03