1.内部存储
内部存储空间有限,在Android系统对应的根目录是 /data/data/,这个目录普通用户是无权访问的,用户需要root权限才可以查看。/data/data目录是按照应用的包名来组织的,每个应用都是属于自己的内部存储目录,而且目录的名称就是该应用的包名,这个目录是在安装应用的时候自动创建的,当应用被卸载后,该目录也会被系统自动删除。所以,如果你将数据存储于内部存储中,其实就是把数据存储到自己应用包名对应的内部存储目录中。每个应用的内部存储目录都是私有的,也就是说内部存储目录下的文件只能被应用自己访问到,其他应用是没有权限访问的。应用访问自己的内部存储目录时不需要申请任何权限。
内部存储目录下各个子目录的作用:
app_webview:主要用于存储webview加载过程中的数据,例如Cookie,LocalStorage等。
cache:主要用于存储使用应用过程中产生的缓存数据。
databases:主要用于存储数据库类型的数据。我们平常创建的数据库文件就是存储在这里。
files:可以在该目录下存储配置文件,敏感数据等。
shared_prefs:用于存储SharedPreference文件。我们使用SharedPreference的时候只指定了文件名,并没有指定存储路径,其实SP的文件就是保存到了这个目录下。
我们主要是使用Context类提供的接口来访问内部存储目录:
1.getDataDir() //获取的目录是/data/user/0/package_name,即应用内部存储的根目录
2.getFilesDir() //获取的目录是/data/user/0/package_name/files,即应用内部存储的files目录
3.getCacheDir() //获取的目录是/data/user/0/package_name/cache,即应用内部存储的cache目录
4.getDir(String name, int mode) //获取的目录是/data/user/0/package_name/app_name,如果该目录不存在,系统会自动创建该目录。
Android4.2以后增加了多用户的功能,为了适应多用户的功能,原来的/data/data/相当于直接链接到当前用户文件夹的,变成了/data/user/0/,所以我们代码中打印出来的路径是/data/user/0,而不是/data/data,说白了/data/data和/data/user/0/是一个东西。
2.外部私有存储
外部私有存储的根目录(这里暂时不考虑SD卡)是 /storage/emulated/0/Android/data/package_name
外部私有存储中的数据会随着App的卸载一起删除
仅仅安装应用不会在/storage/emulated/0/Android/data/目录下生成该应用的外部私有存储目录,只有在应用中调用API访问外部私有存储目录时,才会创建以package_name命名的私有存储目录。
App在访问自己的外部私有存储目录时不需要任何权限
自 Android 7.0 开始,系统对外部存储目录中 应用私有目录的访问权限进一步限制。其他 App 无法通过 file:// 这种形式的 Uri 直接读写其他应用的外部私有存储目录,而是需要通过 FileProvider 访问。
在代码中,我们可以通过以下方式来访问外部私有存储目录:
1.getExternalCacheDir()
/*获取到的目录是/storage/emulated/0/Android/data/package_name/cache,如果该目录不存在,调用这个方法会自动创建该目录。*/
2.getExternalFilesDir(String type)
/* 1.如果type为"",那么获取到的目录是 /storage/emulated/0/Android/data/package_name/files
2.如果type不为空,则会在/storage/emulated/0/Android/data/package_name/files目录下创建一个以传入的type值为名称的目录,例如你将type设为了test,那么就会创建/storage/emulated/0/Android/data/package_name/files/test目录,这个其实有点类似于内部存储getDir方法传入的name参数。但是android官方推荐使用以下的type类型
public static String DIRECTORY_MUSIC = "Music";
public static String DIRECTORY_PODCASTS = "Podcasts";
public static String DIRECTORY_RINGTONES = "Ringtones";
public static String DIRECTORY_ALARMS = "Alarms";
public static String DIRECTORY_NOTIFICATIONS = "Notifications";
public static String DIRECTORY_PICTURES = "Pictures";
public static String DIRECTORY_MOVIES = "Movies";
public static String DIRECTORY_DOWNLOADS = "Download";
public static String DIRECTORY_DCIM = "DCIM";
public static String DIRECTORY_DOCUMENTS = "Documents";
3.外部公有存储
当卸载App时,共有存储目录下的文件不会被删除
应用在访问外部公有目录之前,首先要申请外部存储权限,在Android6.0以后,外部存储权限还要动态申请。
任何应用只要有外部存储权限,都可以访问共有存储目录下的数据。
在代码中,我们可以通过以下方式来访问外部公共存储目录:
1.Environment.getExternalStorageDirectory()
//获取到的目录是/storage/emulated/0,这个也是外部存储的根目录。
2.Environment.getExternalStoragePublicDirectory(String type)
/* 1.如果type为"",那么获取到的目录是外部存储的根目录即 /storage/emulated/0
2.如果type不为空,则会在/storage/emulated/0目录下创建一个以传入的type值为名称的目录,例如你将type设为了test,那么就在外部存储根目录下创建test目录,这个方法和getExternalFilesDir的用法一样。android官方推荐使用以下的type类型,我们在SK卡的根目录下也经常可以看到下面的某些目录。
public static String DIRECTORY_MUSIC = "Music";
public static String DIRECTORY_PODCASTS = "Podcasts";
public static String DIRECTORY_RINGTONES = "Ringtones";
public static String DIRECTORY_ALARMS = "Alarms";
public static String DIRECTORY_NOTIFICATIONS = "Notifications";
public static String DIRECTORY_PICTURES = "Pictures";
public static String DIRECTORY_MOVIES = "Movies";
public static String DIRECTORY_DOWNLOADS = "Download";
public static String DIRECTORY_DCIM = "DCIM";
public static String DIRECTORY_DOCUMENTS = "Documents";*/
另附:在应用之间安全地共享数据,请遵循以下最佳做法,以更安全的方式与其他应用共享您应用的内容:
1.根据需要强制实施只读或只写权限。使用 FLAG_GRANT_READ_URI_PERMISSION 和 FLAG_GRANT_WRITE_URI_PERMISSION 标记,为客户端提供对数据的一次性访问权限。
2.在共享数据时,使用“content://”URI,而不要使用“file://”URI。
FileProvider 的实例会为您执行这一操作。
该
表示files/应用程序内部存储区域子目录中的文件。该子目录与 返回的值相同Context.getFilesDir()。
表示应用程序内部存储区域的缓存子目录中的文件。此子目录的根路径与 返回的值相同getCacheDir()。
表示外部存储区根目录下的文件。此子目录的根路径与 返回的值相同 Environment.getExternalStorageDirectory()。
表示应用程序外部存储区域根目录中的文件。此子目录的根路径与 返回的值相同 Context#getExternalFilesDir(String) Context.getExternalFilesDir(null)。
表示应用程序外部缓存区域根目录中的文件。此子目录的根路径与 返回的值相同 Context.getExternalCacheDir()。
表示应用程序外部媒体区域根目录中的文件。此子目录的根路径与 的第一个结果返回的值相同 Context.getExternalMediaDirs()。
注意:此目录仅在 API 21+ 设备上可用。