可能遇到的问题

android系统自身自带有存储,另外也可以通过sd卡来扩充存储空间。前者好比pc中的硬盘,后者好移动硬盘。 前者空间较小,后者空间大,但后者不一定可用。 开发应用,处理本地数据存取时,可能会遇到这些问题:

  1. 需要判断sd卡是否可用: 占用过多机身内部存储,容易招致用户反感,优先将数据存放于sd卡;
  2. 应用数据存放路径,同其他应用应该保持一致,应用卸载时,清除数据:

    • 标新立异在sd卡根目录建一个目录,招致用户反感
    • 用户卸载应用后,残留目录或者数据在用户机器上,招致用户反感
  3. 需要判断两者的可用空间: sd卡存在时,可用空间反而小于机身内部存储,这时应该选用机身存储;

  4. 数据安全性,本应用数据不愿意被其他应用读写;
  5. 图片缓存等,不应该被扫描加入到用户相册等媒体库中去。

基本操作

  1. 使用外部存储,需要的权限,在 AndoridManifest.xml 中:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    从API 19 / Andorid 4.4 / KITKAT开始,不再需要显式声明这两个权限,除非要读写其他应用的应用数据( $appDataDir )

  2. 判断sd卡可用:

    /**
    * Check if the primary "external" storage device is available.
    *
    * @return
    */
    public static boolean hasSDCardMounted() {
    String state = Environment.getExternalStorageState();
    if (state != null && state.equals(Environment.MEDIA_MOUNTED)) {
    return true;
    } else {
    return false;
    }
    }

存储的用量情况

  • 根据系统用户不同,所能占用的存储空间大小也有不同

    在API level 9及其以上时, File 对象的 getFreeSpace() 方法获取系统root用户可用空间;

    getUsableSpace() 取非root用户可用空间

  • 当有多个存储可用时获取磁盘用量,根据当前系统情况选用合适的存储。

  • 根据系统存储用量,合理设定app所用的空间大小;运行时,也可做动态调整。

  • 在API level 9及其以上的系统,可直接调用 File 对象的相关方法,以下需自行计算:

    @TargetApi(VERSION_CODES.GINGERBREAD)
    public static long getUsableSpace(File path) {
    if (path == null) {
    return -1;
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
    return path.getUsableSpace();
    } else {
    if (!path.exists()) {
    return 0;
    } else {
    final StatFs stats = new StatFs(path.getPath());
    return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks();
    }
    }
    }

路径的规律

一般地,通过 Context  和  Environment 相关的方法获取文件存取的路径。

通过这两个类可获取各种路径,如图:

    ($rootDir)
+- /data -> Environment.getDataDirectory()
| |
| | ($appDataDir)
| +- data/com.srain.cube.sample
| |
| | ($filesDir)
| +- files -> Context.getFilesDir() / Context.getFileStreamPath("")
| | |
| | +- file1 -> Context.getFileStreamPath("file1")
| | ($cacheDir)
| +- cache -> Context.getCacheDir()
| |
| +- app_$name ->(Context.getDir(String name, int mode)
|
| ($rootDir)
+- /storage/sdcard0 -> Environment.getExternalStorageDirectory()
| / Environment.getExternalStoragePublicDirectory("")
|
+- dir1 -> Environment.getExternalStoragePublicDirectory("dir1")
|
| ($appDataDir)
+- Andorid/data/com.srain.cube.sample
|
| ($filesDir)
+- files -> Context.getExternalFilesDir("")
| |
| +- file1 -> Context.getExternalFilesDir("file1")
| +- Music -> Context.getExternalFilesDir(Environment.Music);
| +- Picture -> ... Environment.Picture
| +- ...
|
| ($cacheDir)
+- cache -> Context.getExternalCacheDir()
|
+- ???

各个路径的特性

下面介绍这些路径的特性以及使用中需要注意的细节:

  1. 根目录( $rootDir ):

    • 内部存储路径:  /data , 通过 Environment.getDataDirectory()  获取
    • 外部存储路径:  /storage/sdcard0  (也有类似 /mnt/ 这样的),通过 Environment.getExternalStorageDirectory() 获取

      示例:

        Environment.getDataDirectory():
      /data Environment.getExternalStorageDirectory():
      /storage/sdcard0

  2. 应用数据目录( $appDataDir )
    • 内部储存:  $appDataDir = $rootDir/data/$packageName ,
    • 外部存储:  $appDataDir = $rootDir/Andorid/data/$packageName

    在这些目录下的数据,在app卸载之后,会被系统删除,我们应将应用的数据放于这两个目录中。


  3. 外部存储中,公开的数据目录。 这些目录将不会随着应用的删除而被系统删除,请斟酌使用:

     Environment.getExternalStorageDirectory():
    /storage/sdcard0 // 同 $rootDir
    Environment.getExternalStoragePublicDirectory(""):
    /storage/sdcard0 Environment.getExternalStoragePublicDirectory("folder1"):
    /storage/sdcard0/folder1

  4. 应用数据目录下的目录

    一般的在$appDataDir下,会有两个目录 :

    1. 数据缓存: $cacheDir = $appDataDir/cache :

      • 内部存储: Context.getCacheDir() , 机身内存不足时,文件会被删除
      • 外部存储: Context.getExternalCacheDir()

        外部存储没有实时监控,当空间不足时,文件不会实时被删除,可能返回空对象

        示例:

          Context.getCacheDir():
        /data/data/com.srain.cube.sample/cache Context.getExternalCacheDir():
        /storage/sdcard0/Android/data/com.srain.cube.sample/cache
    2. 文件目录  $filesDir = $appDataDir/files :
      • 内部存储:通过 Context.getFilesDir()  获取

        Context.getFileStreamPath(String name) 返回以 name 为文件名的文件对象, name 为空,则返回  $filesDir  本身

        示例:

          Context.getFilesDir():
        /data/data/com.srain.cube.sample/files Context.getFileStreamPath(""):
        /data/data/com.srain.cube.sample/files Context.getFileStreamPath("file1"):
        /data/data/com.srain.cube.sample/files/file1
      • 外部存储:通过 Context.getExternalFilesDir(String type) ,  type 为空字符串时获取.

        type 系统指定了几种类型:

          Environment.DIRECTORY_MUSIC
        Environment.DIRECTORY_PICTURES
        ...

        示例:

          Context.getExternalCacheDirs():
        /storage/sdcard0/Android/data/com.srain.cube.sample/files Context.getExternalFilesDir(Environment.DIRECTORY_MUSIC)
        /storage/sdcard0/Android/data/com.srain.cube.sample/files/Music

    3. $cacheDir / $filesDir  安全性

      在内部存储中, $cacheDir ,  $filesDir 是app安全的,其他应用无法读取本应用的数据,而外部存储则不是。

      在外部存储中,这两个文件夹其他应用程序也可访问。

      在外部存储中, $filesDir 中的媒体文件,不会被当做媒体扫描出来,加到媒体库中。


    4. $cacheDir / $filesDir  同级目录

      在内部存储中:通过  Context.getDir(String name, int mode) 可获取和  $filesDir  /  $cacheDir 同级的目录

      目录的命名规则为  app_ + name , 通过mode可控制此目录为app私有还是其他app可读写。

      示例:

      Context.getDir("dir1", MODE_PRIVATE):
      Context.getDir: /data/data/com.srain.cube.sample/app_dir1

    5. 特别注意, 对于外部存储,获取 $cacheDir  或者  $filesDir 及其下的路径

      在API level 8 以下,或者空间不足,相关的方法获路径为空时,需要自己构造。

      @TargetApi(VERSION_CODES.FROYO)
      public static File getExternalCacheDir(Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO)) {
      File path = context.getExternalCacheDir(); // In some case, even the sd card is mounted,
      // getExternalCacheDir will return null
      // may be it is nearly full.
      if (path != null) {
      return path;
      }
      } // Before Froyo or the path is null,
      // we need to construct the external cache folder ourselves
      final String cacheDir = "/Android/data/" + context.getPackageName() + "/cache/";
      return new File(Environment.getExternalStorageDirectory().getPath() + cacheDir);
      }

Android文件存储使用参考的更多相关文章

  1. Android 文件存储浅析

    最近做的一个需求和文件存储有关系.由于之前没有系统梳理过,对文件存储方面的知识一直很懵懂.趁着周末有时间,赶紧梳理一波. 这首从网上找到的一张图,很好的概括了外部存储和内部存储. 下面我们再来具体介绍 ...

  2. android文件存储位置切换

    最近有个需求,助手的google卫星地图和OpenCycleMap下载的离线地图数据,要能够在内置存储和外置存储空间之间切换,因为离线瓦片数据非常大,很多户外用户希望将这些文件存储在外置TF卡上,不占 ...

  3. Android文件存储

    文件存储是Android中最基本的一种数据存储方式,它不读存储的内容进行任何的格式化处理,所有数据原封不动的保存在文件之中.如果想用文件存储的方式保存一些较为复杂的数据,就需要定义一套自己的格式规范, ...

  4. android: 文件存储

    数据持久化就是指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或电脑 关机的情况下,这些数据仍然不会丢失.保存在内存中的数据是处于瞬时状态的,而保存在 存储设备中的数据是处于持久状态的,持久化 ...

  5. 转:Android文件存储路径getFilesDir()与getExternalFilesDir的区别

    作为一个开发者,我们经常需要通过缓存一些文件到SD卡中,常见的方式就是,通过: File sdCard = Environment.getExternalStorageDirectory(); 获取S ...

  6. android 文件存储&SharedPreferences

    一.文件存储 文件存储主要是I/O流的操作,没什么好说的,需要注意的是保存文件的各个目录. 下面为常用的目录: public static File getInFileDir(Context cont ...

  7. 程序员带你学习安卓开发系列-Android文件存储

    这是程序员带你学习安卓开发系列教程.本文章致力于面向对象程序员可以快速学习开发安卓技术. 上篇文章:.Net程序员快速学习安卓开发-布局和点击事件的写法 主要讲解了布局和点击事件的写法. 上篇文章补充 ...

  8. Android 文件存储 和 权限管理

    转载请标明出处: :http://blog.csdn.net/huaiyiheyuan/article/details/52473984 android SD卡主要有两种存储方式 Internal . ...

  9. Android数据存储之Android 6.0运行时权限下文件存储的思考

    前言: 在我们做App开发的过程中基本上都会用到文件存储,所以文件存储对于我们来说是相当熟悉了,不过自从Android 6.0发布之后,基于运行时权限机制访问外置sdcard是需要动态申请权限,所以以 ...

随机推荐

  1. Delphi使用XmlHttp获取时间

    uses ComObj, DateUtils; procedure TForm1.Button1Click(Sender: TObject); var XmlHttp: Variant; datetx ...

  2. 为Delphi程序增加UAC功能

    相关资料:http://bbs.csdn.net/topics/320071356# 操作方法: 在Source\VCL目录下应该有这样两个文件sample.manifest和WindowsXP.rc ...

  3. 转:Javascript异步编程的4种方法

    你可能知道,Javascript语言的执行环境是"单线程"(single thread). 所谓"单线程",就是指一次只能完成一件任务.如果有多个任务,就必须排 ...

  4. vc++深入跟踪MFC程序的执行流程

    在MFC程序设计的学习过程中最令人感到难受,甚至于有时会动摇学习者信心的就是一种对于程序的一切细节都没有控制权的感觉.这种感觉来源于学习者不知道一个MFC程序是如何运行起来的(即一个MFC程序的执行流 ...

  5. C++面向对象编程初步

    1,使用const 指针; const int * pOne; //指向整型常量的指针,指向的值不能修改; int * const pTwo; //指向整型的常量指针,指向的值可以修改,但该指针不能再 ...

  6. 04737_C++程序设计_第1章_认识C++的对象

    例1.1 演示使用结构对象的示例程序. //功能:将结构对象的两个域值相加,乘以2再加50 #include <iostream>//包含头文件 using namespace std;/ ...

  7. javascript第四课变量作用域

    局部变量: function f1() { var n1=0;  //局部变量 n1=10; //全局变量,当前页面均可调用 } n1=10;//全局变量 var n1=10;//全局变量 在方法内的 ...

  8. 关于iOS9中的App Transport Security相关说明及适配(转)

    原文:http://my.oschina.net/vimfung/blog/494687 iOS9中新增App Transport Security(简称ATS)特性, 主要使到原来请求的时候用到的H ...

  9. JSON数据格式介绍

    JSON定义     JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于阅读和编写,同一时候也易于机器解析和生成.它基于ECMA262语言规范(1999 ...

  10. HBASE学习笔记--概述

    定义: HBase是一个分布式的.面向列的开源数据库,HBase是Google Bigtable的开源实现,它利用Hadoop HDFS作为其文件存储系统,利用Hadoop MapReduce来处理H ...