Android 文件存储策略

Android的文件存储有两种类型: 内部存储 和 外部存储 。

首先来确定下一些易混淆的概念:

  1. 内部存储 不是内存,内部存储位于系统中很特殊的一个位置。

  2. 外部存储 不一定是 SD 卡, 机身存储也是外部存储。比如 16GB 版本的安卓手机,机子本身就带了外部存储。对于开发来说,最关键的是,我们都是通过相同的 api 来访问可移动的 sdcard 或者手机自带的存储(外部存储)。

  3. 绝对路径是文件的 完整路径,例如d:\java\Hello.java,该路径中包含文件的完整路径d:\java以及文件的全名Hello.java。使用该路径可以唯一的找到一个文件,不会产生歧义。但是使用绝对路径在表示文件时,受到的限制很大,且不能在不同的操作系统下运行,因为不同操作系统下绝对路径的表达形式存在不同。

  4. 相对路径是文件的 部分路径,例如\test\Hello.java,该路径中只包含文件的部分路径\test和文件的全名Hello.java,部分路径是指当前路径下的子路径,例如当前程序在d:\abc下运行,则该文件的完整路径就是d:\abc\test。使用这种形式,可以更加通用的代表文件的位置,使得文件路径产生一定的灵活性。

内部存储

内部存储是指将应用程序中的数据以文件方式存储到设备的内部存储空间中(该文件位于 data/data/your_package_name/ 目录下)。

如果想把文件存储在内部存储中,那么文件 默认只能被当前应用访问,且一个应用所创建的所有文件都在和应用包名相同的目录下。也就是说应用创建于内部存储的文件,与这个应用是关联起来的。当一个应用卸载之后,内部存储中的这些文件也被删除。理论上来讲,如果应用创建的文件设置为可读,那么其他 app 在知道你应用包名的情况下,也是可以访问这些文件的。

需要注意的是,内部存储资源十分珍贵,它也是系统本身和系统应用程序主要的数据存储所在地,一旦内部存储空间耗尽,手机也就无法使用了。所以对于内部存储空间,我们要尽量避免使用。Shared Preferences 和 SQLite 数据库都是存储在内部存储空间上的。内部存储一般用 Context 来获取和操作。

外部存储

don’t be confused by the word “external” here. This directory can
better be thought as media/shared storage. It is a filesystem that can
hold a relatively large amount of data and that is shared across all
applications (does not enforce permissions). Traditionally this is an
SD card, but it may also be implemented as built-in storage in a
device that is distinct from the protected internal storage and can be
mounted as a filesystem on a computer.
关于外部存储,在 api 中 Environment.getExternalStorageDirectory() 方法说得很清楚:

外部存储可认为是一个拥有超大容量媒体存储库(敲重点:相册、音频处理相关的程序生成的文件都要放在这里啊),而且外部存储的表现形式不仅是 sd 卡,还有内置在手机的存储空间。所以不管是 sd 卡还是手机自身内置的存储空间,都是调用相同的 api。

内部存储的存储策略

内部存储根据文件类型大概可以可以分为三种:

  1. 自定义(其路径为/data/data/Your Package Name/app_”your_defined_name”,文件名字系统默认会添加一个前缀“app_”)

  2. Files(其路径为/data//data/Your Package Name/files), api 中提供了比较多的方法来操作该目录下的文件。

  3. cache缓存(其路径为/data/data/Your Package Name/cache)是缓存文件的存放地址。

这三种一般的调用方式如下:

        /* 
         * 1.创建并返回一个指定名称的目录,在这个目录下来存些东西 输出结果为: 
         *   getDir():/data/data/com.example.filedemo/app_abc 
         */  
        File dir1 = getDir("abc", MODE_PRIVATE);  
        Log.i("MainActivity", "getDir():" + dir1.toString());  

        /* 
         * 2.创建并返回一个目录,在这个目录下存储应用程序的数据文件 输出结果为: 
         *   getFilesDir():/data/data/com.example.filedemo/files 
         */  
        File dir2 = getFilesDir();  
        Log.i("MainActivity", "getFilesDir():" + dir2.toString());  

        /* 
         * 3.打开一个输出流对象,通过这个输出流对象可以向abc.txt文件中写入一些数据, 
         * abc.txt文件位于/data/data/com.example.filedemo/files下; 
         */  
        try {  
            FileOutputStream out = openFileOutput("abc.txt", MODE_PRIVATE);  
            out.write("hello world".getBytes());  
            out.flush();  
            out.close();  
        } catch (FileNotFoundException e) {  
            e.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  

        /* 
         * 4.获取一个输入流对象,通过这个输入流对对象读取指定文件,这个文件在/data/data/com.example.filedemo/files下; 
         */  
        try {  
            FileInputStream is = openFileInput("abc.txt");  
            ByteArrayOutputStream out = new ByteArrayOutputStream();  
            int len = 0;  
            byte[] buf = new byte[4];  
            while ((len = is.read(buf)) > 0) {  
                out.write(buf, 0, len);  
                out.flush();  
            }  
            out.close();  
            is.close();  
            Log.i("MainActivity", "openFileInput()读取到的数据:"+out.toString());  
        } catch (FileNotFoundException e) {  
            e.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
 /* 
         * 5.创建并返回一个目录,在这个目录下存储应用程序的缓冲文件,当系统资源不足时,系统清除这下面的文件 
         * 输出结果为:getCacheDir():/data/data/com.example.filedemo/cache 
         */  
        File dir3 = getCacheDir();  
        Log.i("MainActivity", "getCacheDir():" + dir3.toString());  

有创建文件就有删除文件

 /* 
         * 6.删除 /data/data/com.example.filedemo/files文件夹下面某个文件。 
         * 重新执行一下第3条的代码,换个文件名,测试deleteFile()函数。 
         */  
        try {  
            FileOutputStream out = openFileOutput("abc2.txt", MODE_PRIVATE);  
            out.write("hello world".getBytes());  
            out.flush();  
            out.close();  
        } catch (FileNotFoundException e) {  
            e.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
        // 删除刚才创建的文件  
        deleteFile("abc2.txt"); 

内部存储大概是这么些个套路。

外部存储的存储策略

外部存储主要有两种类型:

  1. 公共文件。文件是可以被自由访问,且文件的数据对其他应用或者用户来说都是有意义的,当应用被卸载之后,其卸载前创建的文件仍然保留。比如camera应用,生成的照片大家都能访问,而且camera不在了,照片仍然在。
    getExternalStoragePublicDirectory()方法接受一个字符串常量,即前面写到的Environment的那些静态常量,来确定想要访问的子目录。注意,如果返回的目录不存在,必须在向该目录写入文件前先创建它。

  2. 私有文件。由于是外部存储的原因,即使是私有类型的文件也能被其他程序访问,只不过一个应用私有的文件对其他应用其实是没有访问价值的(恶意程序除外)。外部存储上,应用私有文件的价值在于卸载之后,这些文件也会被删除,类似于内部存储。所有应用程序的外部存储的私有文件都放在根目录的Android/data/下,目录形式为/Android/data//

        /* 
         * 9.创建并返回外部存储文件目录,需要sd卡的的写入数据权限; 
         * 输出结果是:getExternalFilesDir():/mnt/sdcard/Android/data/com.example.filedemo/files/Music 
         */  
        if (status.equals(Environment.MEDIA_MOUNTED)) {  
            File dir4 = getExternalFilesDir(Environment.DIRECTORY_MUSIC);  
            Log.i("MainActivity", "getExternalFilesDir():" + dir4.toString());  
        }   


        /* 
         * 10.创建并返回外部存储文件目录,需要sd卡的的写入数据权限; 
         * 输出结果是:getExternalFilesDir():/mnt/sdcard/Android/data/com.example.filedemo/files/albumName
         */ 
        File file   = newFile(Environment.getExternalStoragePublicDirectory(
        Environment.DIRECTORY_PICTURES), albumName);
        if(!file.mkdirs()) {
            Log.e(LOG_TAG, "Directory not created");
}
    Log.i("MainActivity","getExternalStoragePublicDirectory():"+file.toString());

        /* 
         * 11.创建并返回外部存储缓冲目录,需要sd卡的写入数据权限; 
         * 输出结果是:getExternalCacheDir():/mnt/sdcard/Android/data/com.example.filedemo/cache 
         */  
        if (status.equals(Environment.MEDIA_MOUNTED)) {  
            File dir5 = getExternalCacheDir();  
            Log.i("MainActivity", "getExternalCacheDir():" + dir5.toString());  
        }   

文件的多级存储

多级存储需要逐级创建文件夹,再强调一下,真的需要一级一级地创建,如果直接指向目标多级文件夹的地址,前序文件夹又没有建立,那么这个地址就访问不了。

          //文件夹目录"/sdcard/FirstFolder/SecondFolder",多级目录必须逐一创建  

             public static String FirstFolder="FirstFolder";//一级目录  

             public static String SecondFolder="SecondFolder";//二级目录  

             /*ALBUM_PATH取得机器的SD卡位置,File.separator为分隔符“/”*/  

             private final static String ALBUM_PATH=Environment.getExternalStorageDirectory()+File.separator+FirstFolder+File.separator;  

             private final static String Second_PATH=ALBUM_PATH+SecondFolder+File.separator;  

创建过程

//检查手机上是否有外部存储卡  

             boolean sdCardExist = Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);  

             if(!sdCardExist)  

             {//如果不存在SD卡,进行提示  

                  Toast.makeText(YuanTuActivity.this, "请插入外部SD存储卡", Toast.LENGTH_SHORT).show();  

             }else{//如果存在SD卡,判断文件夹目录是否存在  

                 //一级目录和二级目录必须分开创建  

                 File dirFirstFile=new File(ALBUM_PATH);//新建一级主目录  

                 if(!dirFirstFile.exists()){//判断文件夹目录是否存在  

                      dirFirstFile.mkdir();//如果不存在则创建  

                 }  

                 File dirSecondFile=new File(Second_PATH);//新建二级主目录  

                 if(!dirSecondFile.exists()){//判断文件夹目录是否存在  

                      dirSecondFile.mkdir();//如果不存在则创建  

                 }  

             } 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值