• 如何导出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对应文件夹下,然后再进行读取,这样一来,效率极低,并且对数据库做完改动后,改动也没有办法同步到源数据库中(也就是数据库会自动还原)。那么这个问题该输入解决呢?以后有时间,再整理一篇博客,说一些这个问题。

  • 相关阅读:
    halcon算子翻译——close_framegrabber
    switch case 注意事项+1 及 case合并综合练习例子
    switch case 注意事项
    switch case
    equals()方法 与 == 区别
    if else 选择机构 _多重if选择机构_if选择结构嵌套(综合练习题——code)
    程序流程控制三大结构
    国外著名java论坛(FQ也要看!)
    键盘接收用户输入案例1——计算两数和
    键盘接收用户输入案例2(案例内容包含键盘接收 int、String、Char、double、boolean)等类型及介绍
  • 原文地址:https://www.cnblogs.com/YaoJianXun/p/7522430.html
Copyright © 2020-2023  润新知