如何导出android内部存储的文件(不用root)

  这段时间公司项目,涉及到数据缓存,由于需要缓冲的数据太多、太大,通过网络请求,再缓存到本地sqlite数据库,太费时间,消耗流量。所以准备先在本地保存一个标准版sqlite数据库(包含数据),打包到apk文件里,以后需要的操作就是更新数据,这样一来,请求和操作的数据就很小了。

  那么问题来了,如何把标准版的sqlite数据库文件(db格式)从内部存储空间里面导出,然后放到项目中assets文件夹下?

  想从内部存储空间里拷贝东西,首先要root,手机要root,APP也要获得root权限。这篇博客不讲如何通过root拷贝内容,因为这种办法真的很蠢,root手机会给手机带来不可逆的改变,如果手机很贵的话,尽量不要root;即便手机root后,app也好获得root权限,很麻烦,而且国内手机厂商rom不同,很多手机即便按照步骤一步步root了,也不能查看和赋值内部存储空间里的文件。

  那么怎么实现呢?一个简单到可笑的办法(获取这是android系统安全性上的漏洞),在代码中,我们可以访问、读取内部存储空间里的东西,也可以读写SD卡等外部存储空间(要添加相应权限),那么我们就可以通过IO的方法,将内部存储空间中的文件,拷贝到外部存储空间,然后再从外部存储空间里拷贝我们需要的东西就OK了。

  实现方式:

1、添加系统权限:

在AndroidManifest.xml中添加读写SD卡等操作权限:

    <!-- 写入扩展存储,向扩展卡写入数据-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

2、从内部存储空间通过IO的方式拷贝到SD卡和外部存储空间:

这个时候,已经通过网络请求,将拿到的JSON数据写入到sqlite数据库中了。直接拷贝就好:

/**
     * 拷贝内部存储空间的数据库到外部
     *
     * @throws FileNotFoundException
     */
    public void copyDBFile() throws FileNotFoundException {
        File toDir = new File(Field.DB_PATH_SD);   //外部存储文件夹
        if (!toDir.exists()) {
            toDir.mkdirs();
        }

        File toDb = new File(Field.DB_PATH_SD + App.BaseDB.dbName); //外部存储数据库
        File fromDir = new File(Field.DB_PATH + App.BaseDB.dbName); //内部存储数据库

        InputStream is;
        OutputStream os;
        is = new FileInputStream(fromDir);
        os = new FileOutputStream(toDb);
        byte[] buffer = new byte[1024];
        int length;
        try {
            /**
             * 拷贝过程
             */
            while ((length = is.read(buffer, 0, buffer.length)) > 0) {
                os.write(buffer, 0, length);
            }

            os.flush();
            os.close();
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

相关常量:

/**
     * 内部数据库路径
     */
    public static final String DB_PATH = File.separator + "data"
            + Environment.getDataDirectory().getAbsolutePath() + File.separator
            + MyApplication.getInstance().getPackageName() + File.separator + "databases" + File.separator;

    /**
     * 外部数据库路径
     */
    public static final String DB_PATH_SD = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "tdr" + File.separator;

 public static class BaseDB{
        public static final int version=1;
        public static final String dbName="base.db";
    }

3、在需要的地方,调用copyDBFile()

           
            try {
                //拷贝工具类通过单例获取
                BaseDBHelper.getInstance().copyDBFile();
            } catch (FileNotFoundException e) {
                Log.e(TAG, "fileNotFount");
                Log.e(TAG, e.getMessage());
                Log.e(TAG, e.toString());
                e.printStackTrace();
            }        

执行完成以后,就可以直接在手机文件夹里看到需要的db文件了:

 

如此,就可以在非root的前提下,拷贝出内部存储空间里的文件了。不得不说,这也许是android无意的一个安全漏洞吧!因为这个真的很蠢,就好比:一家人有一个保险柜,里面放着家里的财产,贼要是想从保险柜里直接拿走财物是不可以的,但是如果贼先把钱从保险柜里拿到客厅,再从客厅拿走,就完全可以,这样拿走,不仅没有约束,家里主人还会主动把保险柜密码告诉你,把家里的大门为你敞开。。。。。。

4、后记

我之前介绍公司项目的时候,提到:我会把db文件通过离线的方式拷贝到项目的assets文件夹下,然后需要操作数据库的时候,就操作assets文件夹里的数据库。但是这样做会有一个很大的性能上的问题:

sqlite数据库的读写,只能读写/data/...中的数据库文件,如此一来,每次读写或修改assets中的数据库的时候,就要先把assets的数据库拷贝到data对应文件夹下,然后再进行读取,这样一来,效率极低,并且对数据库做完改动后,改动也没有办法同步到源数据库中(也就是数据库会自动还原)。那么这个问题该输入解决呢?以后有时间,再整理一篇博客,说一些这个问题。

 

 

posted @ 2017-09-14 19:50  建勋  阅读(6043)  评论(0编辑  收藏  举报