存储的类别
Android 提供两类物理存储位置:内部存储空间和外部存储空间。 在大多数设备上,内部存储空间小于外部存储空间,内部存储是手机系统自带的存储,一般空间都比较小,外部存储一般是SD卡的存储,空间一般都比较大,但不一定可用或者剩余空间可能不足。 默认情况下,应用本身存储在内部存储空间中,可以在应用的清单文件中指明偏好设置,以便将应用安装到外部存储空间:
<manifest ...
android:installLocation="preferExternal">
...
</manifest>
权限
与存储相关的权限: READ_EXTERNAL_STORAGE、 WRITE_EXTERNAL_STORAGE、 MANAGE_EXTERNAL_STORAGE。
存储使用
应用专属存储目录
1.内部存储空间目录:这些目录既包括用于存储持久性文件的专属位置,也包括用于存储缓存数据的其他位置。(对应清除数据和清楚缓存)系统会阻止其他应用访问这些位置,并且在 Android 10(API 级别 29)及更高版本中,系统会对这些位置进行加密。这些特征使得这些位置非常适合存储只有应用本身才能访问的敏感数据。 这些目录的空间通常比较小。在将应用专属文件写入内部存储空间之前,应用应查询设备上的可用空间。
创建
File.createTempFile(filename, null, context.getCacheDir());
获取
File cacheFile = new File(context.getCacheDir(), filename);
当设备的内部存储空间不足时,Android 可能会删除这些缓存文件以回收空间。因此,请在读取前检查缓存文件是否存在。
删除
cacheFile.delete();
context.deleteFile(cacheFileName);
2.外部存储空间目录:这些目录既包括用于存储持久性文件的专属位置,也包括用于存储缓存数据的其他位置。虽然其他应用可以在具有适当权限的情况下访问这些目录,但存储在这些目录中的文件仅供您的应用使用。如果您明确打算创建其他应用能够访问的文件,您的应用应改为将这些文件存储在外部存储空间的共享存储空间部分。
在 Android 4.4(API 级别 19)或更高版本中,应用无需请求任何与存储空间相关的权限即可访问外部存储空间中的应用专属目录。
在搭载 Android 9(API 级别 28)或更低版本的设备上,只要您的应用具有适当的存储权限,就可以访问属于其他应用的应用专用文件。为了让用户更好地管理自己的文件并减少混乱,以 Android 10(API 级别 29)及更高版本为目标平台的应用在默认情况下被授予了对外部存储空间的分区访问权限(即分区存储)。启用分区存储后,应用将无法访问属于其他应用的应用专属目录。
验证存储空间的可用性 比如SD卡的话可能会被用户移除或者损坏,读写之前要验证可用性
private boolean isExternalStorageWritable() {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
}
private boolean isExternalStorageReadable() {
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ||
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY);
}
持久性文件访问
File appSpecificExternalDir = new File(context.getExternalFilesDir(null), filename);
如果应用在搭载 Android 4.4(API 级别 19)或更高版本的设备上运行,从外部存储空间访问不需要任何权限 创建外部存储空间的缓存文件
File externalCacheFile = new File(context.getExternalCacheDir(), filename);
移除缓存文件
externalCacheFile.delete();
如果是媒体内容 应用支持使用仅在您的应用内对用户有价值的媒体文件,最好将这些文件存储在外部存储空间中的应用专属目录中:
@Nullable
File getAppSpecificAlbumStorageDir(Context context, String albumName) {
File file = new File(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES), albumName);
if (file == null || !file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}
API 常量提供的目录名称: public static String DIRECTORY_MOVIES = “Movies”; public static String DIRECTORY_DOCUMENTS = “Documents”;等等
getExternalFilesDir(null)!!.absolutePath 输出的路径:/storage/emulated/0/Android/data/packagename/files
3.查询可用空间 您可以通过调用 getAllocatableBytes() 查出设备可以为应用提供多少空间。getAllocatableBytes() 的返回值可能大于设备上的当前可用空间量。这是因为系统已识别出可以从其他应用的缓存目录中移除的文件。
private static final long NUM_BYTES_NEEDED_FOR_MY_APP = 1024 * 1024 * 10L;
StorageManager storageManager =
getApplicationContext().getSystemService(StorageManager.class);
UUID appSpecificInternalDirUuid = storageManager.getUuidForPath(getFilesDir());
long availableBytes =
storageManager.getAllocatableBytes(appSpecificInternalDirUuid);
if (availableBytes >= NUM_BYTES_NEEDED_FOR_MY_APP) {
storageManager.allocateBytes(
appSpecificInternalDirUuid, NUM_BYTES_NEEDED_FOR_MY_APP);
} else {
Intent storageIntent = new Intent();
storageIntent.setAction(ACTION_MANAGE_STORAGE);
}
无需检查可用空间即可保存文件。可以尝试立即写入文件,然后在出现 IOException 时将其捕获。
如果用户卸载应用,系统会移除保存在应用专属存储空间中的文件。 不应使用此存储空间保存用户希望独立于应用而保留的任何内容。例如,如果应用允许用户拍摄照片,用户会希望即使卸载应用后仍可访问这些照片。因此,您应改为使用共享存储空间将此类文件保存到适当的媒体集合中。
外部存储公共目录 Environment.getExternalStorageDirectory() 绝对路径: /storage/emulated/0
共享存储目录
Android 提供用于存储和访问以下类型的可共享数据的 API: **媒体内容:**系统提供标准的公共目录来存储这些类型的文件,这样用户就可以将所有照片保存在一个公共位置,将所有音乐和音频文件保存在另一个公共位置,依此类推。您的应用可以使用此平台的 MediaStore API 访问此内容。 文档和其他文件:系统有一个特殊目录,用于包含其他文件类型,例如 PDF 文档和采用 EPUB 格式的图书。您的应用可以使用此平台的存储访问框架访问这些文件。 **数据集:**在 Android 11(API 级别 30)及更高版本中,系统会缓存多个应用可能使用的大型数据集。这些数据集可为机器学习和媒体播放等用例提供支持。应用可以使用 BlobStoreManager API 访问这些共享数据集。
访问共享目录的媒体文件
Cursor cursor = getApplicationContext().getContentResolver().query(
MediaStore.media-type.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
);
while (cursor.moveToNext()) {
}
如果您的应用在搭载 Android 9 或更低版本的设备上使用,或者您的应用暂时停用分区存储,您必须请求 READ_EXTERNAL_STORAGE 权限才能访问媒体文件。如果要修改媒体文件,您还必须请求 WRITE_EXTERNAL_STORAGE 权限。
|