Android存储空间详解
一、存储空间
1 存储介质与存储结构
Android的存储空间用于数据持久化存储,属于ROM存储介质,这意味着即使设备关机或应用程序退出,数据也不会丢失,这与RAM存储介质不同,RAM中的数据在应用关闭或设备关机时会消失,为了实现数据持久化,Android系统采用了多种存储方式,包括文件存储、数据库存储和SharedPreferences存储等。
从存储结构来看,Android系统的内核基于Linux内核,因此其文件目录结构和Linux系统类似,Android使用虚拟文件系统(VFS),其根目录为“/”,在该根目录下有许多子目录,如/data、/system、/mnt、/storage等,这些目录分别用于不同用途,data目录主要用于存放用户数据,而/system目录则包含系统文件。
2 内部存储 vs 外部存储
在Android设备中,存储空间主要分为内部存储和外部存储:
内部存储:通常指设备自带的存储空间,位于/data目录下,这部分存储专用于安装的应用及其私有数据,并且对普通用户不可见,只有具备root权限的用户才能访问此目录。
外部存储:一般指SD卡或者机身内模拟的SD卡部分,主要用于公共数据的存储,在Android 4.4之前,外部存储主要指插入的SD卡;而在Android 4.4之后,很多设备将机身存储划分为内部存储和外部存储两部分。
二、内部存储详解
1 内部存储
内部存储是指/data目录下的空间,通常用于存储应用程序的私有数据,如数据库、共享偏好设置和缓存文件,每个应用在安装后会在/data/data/目录下创建一个以包名命名的文件夹,该文件夹用于存储应用的私有数据,微信的内部存储路径为/data/data/com.tencent.mm/。
2.1.1 典型内部存储目录结构
app_webview:用于存储WebView加载过程中的数据,如Cookie和LocalStorage。
cache:用于存储应用运行过程中产生的缓存数据。
code_cache:包含运行时代码优化产生的缓存。
databases:存储应用创建的数据库文件。
files:用于存放应用的其他文件。
lib:存放应用依赖的so库文件。
shared_prefs:用于存储SharedPreference文件。
2 内部存储 私有目录
2.2.1 特点
安全性高:应用卸载时,内部存储中的相关数据也会被删除,确保数据不会被其他应用访问。
无需权限:应用可以直接访问自己的内部存储目录,无需额外申请权限。
适用于敏感数据:由于其高安全性,内部存储适合保存隐私性或敏感性高的数据。
2.2.2 API相关
开发者可以通过以下API访问内部存储:
获取内部存储目录:context.getDataDir()
返回/data/data/packagename目录。
获取缓存目录:context.getCacheDir()
返回/data/data/packagename/cache目录。
获取Files目录:context.getFilesDir()
返回/data/data/packagename/files目录。
创建私有目录:context.getDir("dirname", mode)
在内部存储中创建一个私有目录。
2.2.3 示例代码
// 获取内部存储的Files目录 File filesDir = context.getFilesDir(); // 在Files目录下创建一个文件 File file = new File(filesDir, "example.txt"); try { FileOutputStream fos = new FileOutputStream(file); fos.write("Hello, internal storage".getBytes()); fos.close(); } catch (IOException e) { e.printStackTrace(); }
3 内部存储 公有目录
虽然内部存储主要是私有的,但某些情况下应用也可以创建公有目录供其他应用访问,不过,这需要谨慎处理,因为可能引发安全隐患。
三、外部存储详解
1 外部存储
外部存储通常指SD卡或者机身内模拟的SD卡部分,主要用于公共数据的存储,在Android 4.4之后,很多设备将机身存储划分为内部存储和外部存储两部分,外部存储的最外层目录是storage文件夹,也可能是mnt文件夹,具体取决于设备的厂商。
2 外部存储 私有目录
3.2.1 特点
无需权限:在Android 6.0及更高版本中,应用可以直接访问自己应用专属的外部存储目录,无需额外申请权限。
隔离性强:每个应用都有自己的专属目录,其他应用无权访问。
适用于多媒体文件:适合存储图片、音频、视频等文件。
3.2.2 API相关
开发者可以通过以下API访问外部存储的私有目录:
获取外部存储私有目录:context.getExternalFilesDir(null)
返回/storage/emulated/0/Android/data/packagename目录。
获取外部缓存目录:context.getExternalCacheDir()
返回/storage/emulated/0/Android/data/packagename/cache目录。
3.2.3 示例代码
// 获取外部存储的Files目录 File externalFilesDir = context.getExternalFilesDir(null); // 在外部Files目录下创建一个文件 File externalFile = new File(externalFilesDir, "example_external.txt"); try { FileOutputStream fos = new FileOutputStream(externalFile); fos.write("Hello, external storage".getBytes()); fos.close(); } catch (IOException e) { e.printStackTrace(); }
3 外部存储 公共目录
3.3.1 特点
需要权限:在Android 6.0及更高版本中,读写公共目录需要申请READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限。
适用于共享文件:公共目录适合存放需要与其他应用共享的文件,如媒体文件。
3.3.2 API相关
开发者可以通过以下API访问外部存储的公共目录:
获取公共存储目录:Environment.getExternalStorageDirectory()
返回/storage/emulated/0目录。
获取公共下载目录:Environment.getExternalStoragePublicDownloadDirecotry()
返回/storage/emulated/0/Download目录。
3.3.3 示例代码
// 检查并申请权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); } // 获取公共存储的Download目录 File downloadDir = Environment.getExternalStoragePublicDownloadDirectory(); // 在Download目录下创建一个文件 File downloadFile = new File(downloadDir, "example_public.txt"); try { FileOutputStream fos = new FileOutputStream(downloadFile); fos.write("Hello, public storage".getBytes()); fos.close(); } catch (IOException e) { e.printStackTrace(); }
四、分区存储机制(Scoped Storage)
1 分区存储
从Android 10(API级别29)开始,引入了分区存储机制,旨在更好地管理外部存储上的文件,同时保护用户的隐私,分区存储限制了应用对外部存储的访问权限,除非用户明确允许,否则应用只能访问其专属的外部存储目录以及特定类型的媒体文件。
2 分区存储的影响
增强隐私:用户在使用分区存储的设备上安装应用时,系统会自动为每个应用创建一个专属的外部存储目录,其他应用无法访问该目录。
简化权限管理:应用无需在清单文件中声明READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE权限即可访问其专属目录,如果需要访问其他类型的文件,仍需申请相应的权限。
兼容性考虑:对于targetSdkVersion低于29的应用,分区存储机制不会生效,但这些应用在Android 11及更高版本上运行时,仍会受到一定的限制。
3 适配分区存储的方法
为了适配分区存储机制,开发者可以采取以下措施:
使用MediaStore API:对于媒体文件,推荐使用MediaStore API进行操作,而不是直接访问文件系统,这样可以确保应用在不同版本的Android系统上都能正常运行。
请求特殊权限:如果应用需要访问其他应用生成的文件,可以使用Storage Access Framework(文档选择器)或请求QUERY_ALL_PACKAGES权限。
优化应用逻辑:尽量减少对公共外部存储的依赖,优先考虑使用应用专属目录或云端存储解决方案。
五、归纳
Android系统提供了丰富的存储机制,以满足不同类型的数据持久化需求,内部存储适合保存应用的私有数据,而外部存储则更适合存放需要与其他应用共享的公共数据,随着Android版本的不断更新,新的存储机制如分区存储也在逐步完善,为用户提供更好的隐私保护和使用体验,开发者应根据具体需求选择合适的存储方式,并遵循最佳实践以确保应用的稳定性和安全性。