最近做的一个需求和文件存储有关系。由于之前没有系统梳理过,对文件存储方面的知识一直很懵懂。趁着周末有时间,赶紧梳理一波。

这首从网上找到的一张图,很好的概括了外部存储和内部存储。

下面我们再来具体介绍相关知识和内容。

内部存储

内部存储,位于data/data/包名/路径下

是否需要用户权限:否

是否能被其他应用访问:否

卸载应用数据是否被删除:是

内部存储控件不需要用户权限,这意味着我们不需要用户去授权下面的权限:

android.permission.WRITE_EXTERNAL_STORAGE
android.permission.READ_EXTERNAL_STORAGE

对于设备中每一个安装的 App,系统都会在 data/data 目录下以应用程序包名自动创建与之对应的文件夹,可以直接读写该目录下的文件。而且该目录下的文件不能被其他应用访问。这也就保证了我们应用内部存储的文件的安全性和隐私性,如果我们需要查看自己应用内部的文件,我们可以通过 Android Studio的Device File Explore 工具进行访问:

   

通过这个,可以查看对应应用的存储文件。

/data/data/应用名/cache :存放的是APP的缓存信息

/data/data/应用名/code_cache :在运行时存放应用产生的编译或者优化的代码

/data/data/应用名/files : 存放APP的文件信息

还有一些运行时,产生的文件夹,例如调用 SharedPreference 所产生的 /data/data/应用包名/shared_prefs 目录,存放着 app 的 SharedPreference 所产生的 xml 文件,还有调用数据库所产生的 **/data/data/应用包名/databases/** 文件夹,这里就不一一举例。

从技术上来讲如果你在创建内部存储文件的时候将文件属性设置成可读,其他 app 能够访问自己应用的数据,前提是他知道你这个应用的包名,如果一个文件的属性是私有(private),那么即使知道包名其他应用也无法访问。 内部存储空间十分有限,因而显得可贵,另外,它也是系统本身和系统应用程序主要的数据存储所在地,一旦内部存储空间耗尽,手机也就无法使用了。所以对于内部存储空间,我们要尽量避免使用。Shared Preferences 和 SQLite 数据库都是存储在内部存储空间上的。内部存储一般用 Context 来获取和操作。
访问内部存储的API方法:

  1. getFilesDir().getAbsolutePath()  : /data/user/0/com.example.myapplication/files

  2. getCacheDir().getAbsolutePath() :  /storage/emulated/0/Android/data/com.example.myapplication/cache

  3. getDir(“myFile”, MODE_PRIVATE).getAbsolutePath()  : /data/user/0/com.example.myapplication/app_myfile

  4. getCodeCacheDir().getAbsolutePath() : /data/user/0/com.example.myapplication/code_cache  ,要求Android5.0+

外部存储

概念:最容易混淆的是外部存储,因为老的 Android 系统的跟新的 Android 系统是有差别的,很多人去网上查找资料,看了一下以前的资料,又看了一下现在的资料,但是发现它们说法不一样然后就困惑了。

首先说一个大家普遍的概念 "如果在 pc 机上是区分外部存储和内部存储的话,那么电脑自带的硬盘算是内部存储,U盘或者移动硬盘就是外部存储了。" 因此很多人带着这样的理解去看待安卓手机,把内置存储(机身存储)当做内部存储,而把扩展的 SD 卡当做是外部存储。

这么认为确实没错,因为在 4.4(API19)以前的手机上确实是这样的,手机自身带的存储卡就是内部存储,而扩展的SD卡就是外部存储。

但是从 4.4 的系统开始,很多的中高端机器都将自己的机身存储扩展到了 8G 以上,比如有的人的手机是 16G 的,有的人的手机是 32G 的,但是这个 16G,32G 是内部存储吗,不是的,它们依然是外部存储。

也就是说 4.4 系统及以上的手机将机身存储存储(手机自身带的存储叫做机身存储)在概念上分成了 "内部存储internal" 和 "外部存储external" 两部分。既然 16G,32G 是外部存储,那有人又有疑惑了,那 4.4 系统及以上的手机要是插了 SD 卡呢,SD 卡又是什么呢,如果 SD 卡也是外部存储的话,那怎么区分机身存储的外部存储跟 SD 卡的外部存储呢?

对,SD卡也是外部存储,那怎么区分呢,在4.4以后的系统中,API提供了这样一个方法来遍历手机的外部存储路径:

File[] files;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
files = getExternalFilesDirs(Environment.MEDIA_MOUNTED);
for(File file:files){
Log.e("main",file);
}
}

如果你的手机插了SD卡的话,那么它打印的路径就有两条了,例如我的华为荣耀 7 插了SD卡,它的结果如下:

/storage/emulated/0/Android/data/packname/files/mounted
/storage/B3E4-1711/Android/data/packname/files/mounted

其中 /storage/emulated/0 目录就是机身存储的外部存储路径,而 /storage/B3E4-1711/ 就是 SD 卡的路径,他们统称为外部存储。

一般对于外部存储可以分为两类,外部公有和外部私有。

外部公有

是否需要用户权限:

是否能被其他应用访问:

卸载应用数据是否被删除:

公共目录必须需要用户授权读写的权限,这意味着我们需要在 AndroidManifest.xml 中注册用户权限。

    <!-- 外部存储写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

并且在 Android 6.0 系统之后需要申请用户权限,并获得用户授权,才能读写文件。

公共目录相对开放,我们可以访问其他APP存在公共目录下的文件,并且当 APP 被删除时,并不会删除应用存在公共目录下的文件。

我们可以通过 Environment 对象,访问读写公共目录的文件。

在对外部存储进行读写的时候,应该先判断一下外部存储的状态,是否能够支持读写。

Environment.getExternalStorageState()
/** {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
* {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
* {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
* {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
* {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}
*/

只有在返回值为 MEDIA_MOUNTED 表示当前是可正常读写的。

接下来让我们看看相关的API。

1. Environment.getExternalStorageDirectory() : /storage/emulated/0

2. Environment.getExternalStoragePublicDirectory(String type)
Environment.getExternalStoragePublicDirectory(DIRECTORY_DOCUMENTS).getAbsolutePath() : /storage/emulated/0/Documents
    Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getAbsolutePath() : /storage/emulated/0/Music

外部私有

是否需要用户权限:4.4以上不需要

是否能被其他应用访问:否

卸载应用数据是否被删除:是

私有目录,在 Android4.4 系统以上。不需要注册和用户授权外部私有存储的读写的权限,就可以在应用的外部私有进行读写文件。并且文件不能被其他应用所访问,具有较好的隐私性和安全性,并且在用户删除的时候,对应的应用私有目录也会被删除。

私有目录地址:/storage/emulated/0/Android/data/应用包名

相关API如下:

getExternalCacheDir().getAbsolutePath()  // /storage/emulated/0/Android/data/com.example.myapplication/cache

getExternalFilesDir("mytest").getAbsolutePath() // /storage/emulated/0/Android/data/com.example.myapplication/files/mytest
getExternalFilesDir(null).getAbsolutePath()  // /storage/emulated/0/Android/data/com.example.myapplication/files

总结

本文详细介绍了 android 的外部存储和私有存储。大家在有保存文件的需求的时候,根据自己的需要,选择到底是存在哪里比较合适。内部存储相对较小,不介意把一些大文件存在其中。应该存在外部存储会更好。对于可以给其他文件访问的,可以存在外部存储的公有文件里面。

 

参考文献

Android 文件存储浅析的更多相关文章

  1. Android文件存储

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

  2. android: 文件存储

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

  3. android文件存储位置切换

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

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

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

  5. android 文件存储&SharedPreferences

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

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

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

  7. Android文件存储使用参考

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

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

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

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

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

随机推荐

  1. 【转】HBase中Zookeeper,RegionServer,Master,Client之间关系

    在2.0之前HDFS中只有一个NameNode,但对于在线的应用只有一个NameNode是不安全的,故在2.0中对NameNode进行抽象,抽象成NamService其下包含有多个NameNode,但 ...

  2. Elastic认证考试,请先看这一篇

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/wojiushiwo987/article ...

  3. 去除List集合中的重复值(四种好用的方法)(基本数据类型可用)

    最近项目中需要对list集合中的重复值进行处理,大部分是采用两种方法,一种是用遍历list集合判断后赋给另一个list集合,一种是用赋给set集合再返回给list集合. 但是赋给set集合后,由于se ...

  4. HDU3686 Traffic Real Time Query【缩点+lca】

    题目 City C is really a nightmare of all drivers for its traffic jams. To solve the traffic problem, t ...

  5. em(倍)与px的区别

    在国内网站中,包括三大门户,以及“引领”中国网站设计潮流的蓝色理想,ChinaUI等都是使用了px作为字体单位.只有百度好歹做了个可调的表率.而 在大洋彼岸,几乎所有的主流站点都使用em作为字体单位, ...

  6. 一.5.序列化应用之服务器制造厂与型号app功能

    1.环境准备: (python36env) [vagrant@CentOS7 apps]$ django-admin startapp manufacturer (1)激活:'manufacturer ...

  7. SpringBoot下Druid连接池的使用配置

    Druid是一个JDBC组件,druid 是阿里开源在 github 上面的数据库连接池,它包括三部分: * DruidDriver 代理Driver,能够提供基于Filter-Chain模式的插件体 ...

  8. 【必读】前端需要懂的 APP 容器原理

    App 容器,简言之,App 承载某类应用(H5/RN/Weex/小程序/Flutter ...)的运行环境,可主动干预并进行功能扩展,达到丰富能力.优化性能.提升体验的目的,如页面数据预取(pref ...

  9. HotSpot二分模型(1)

    HotSpot采用了OOP-Klass模型来描述Java类和对象.OOP(Ordinary Object Pointer)指的是普通对象指针,而Klass用来描述对象的具体类型. 那么为何要设计这样一 ...

  10. POJ1017贪心

    题意:小P开了一家淘宝店铺,店铺里所有的商品高度都为h,但长和宽分别为1*1,2*2,3*3,4*4,5*5,6*6六种规格.这一天来了一个大客户,他订购了很多物品.所以小P需要将东西都邮寄给他,但是 ...