内部或外部存储
internal
和external
存储的名字来源于早期的Android设备,它提供了内置的非易失性内存(内部存储),加上一个可移动的存储介质,比如 SD 卡(外部存储)
而现在为了兼容性,直接将存储空间划分为“内部”和“外部”分区,即没有移动存储介质,但同样有两个存储空间,对于API来说,不管外部存储是否是可以移动的,其执行效果是相同的
内部存储:
- 它始终可用
- 只有应用可以访问此处保存的文件
- 当用户卸载应用时,系统会从内部存储中移除应用的所有文件。
当希望确保用户或其他应用均无法访问对应的文件时,内部存储是最佳选择。
外部存储:
- 并非始终可用,因为用户可采用 USB 存储设备的形式装载外部存储,并在某些情况下会从设备中将其移除。
- 它是全局可读的,因此此处保存的文件可能不受控制地被读取。
- 当用户卸载应用时,只会移除通过
getExternalFilesDir()
获取到的目录下的文件
对于无需访问限制以及希望与其他应用共享或允许用户使用计算机访问的文件,外部存储是最佳位置。
权限
应用始终具有在其内部存储目录中进行读写的权限
要向外部存储写入信息,必须在清单文件中请求WRITE_EXTERNAL_STORAGE
权限。
从 Android 4.4 (API level 19)开始,外部存储设备上的私有文件,无需 WRITE_EXTERNAL_STORAGE
权限(即读写通过getExternalFilesDir(String)
和getExternalCacheDir()
获取的目录下对应的文件)
例如, 应用 com.example.foo
可以自由访问外部存储上的 Android/data/com.example.foo/
。
Android 6.0以后,需要运行时请求写外部存储的权限
<manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
</manifest>
文件保存到内部存储中
getFilesDir()
返回文件系统的绝对路径,与通过openFileOutput(String, int)
创建文件的存储位置一致
getCacheDir()
设备的内部存储空间不足时,Android 可能会删除这些缓存文件以回收空间。 但不应该依赖系统来清理这些文件, 而应该始终自行维护缓存文件,使其占用的空间保持在合理的限制范围内(例如 1 MB)。 当用户卸载您的应用时,这些文件也会被移除
创建缓存文件:
public File getTempFile(Context context, String url) {
File file;
try {
String fileName = Uri.parse(url).getLastPathSegment();
file = File.createTempFile(fileName, null, context.getCacheDir());
} catch (IOException e) {
// Error while creating file
}
return file;
}
保存在外部存储
公有文件
供其他应用和用户自由使用的文件。 当用户卸载您的应用时,用户应仍可以使用这些文件,例如Download,Music,Pictures等
通过方法
getExternalStoragePublicDirectory()
//向其传递需要的目录类型,例如 DIRECTORY_MUSIC、DIRECTORY_PICTURES、 DIRECTORY_RINGTONES
public File getAlbumStorageDir(String albumName) {
// 获取公有的照片目录
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}
私有文件
属于应用且在用户卸载用时会删除的文件。
例如,应用下载的其他资源或临时介质文件。
getExternalFilesDir(String type)
//使用外部存储上的私有存储目录,type 参数指定子目录的类型(例如 DIRECTORY_MOVIES),null会获得私有目录的根目录。
getExternalCacheDir(String type)
//缓存文件保存到的外部存储目录,用户卸载应用,文件也会被自动删除
type参数的指定子目录类型
//创建个人相册的目录
public File getAlbumStorageDir(Context context, String albumName) {
// Get the directory for the app's private pictures directory.
File file = new File(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}
查询外部存储状态,是否可以读写或只能读
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
删除文件
myFile.delete();//文件自行删除
myContext.deleteFile(fileName);//删除内部存储对应的文件
Environment.getExternalStorageDirectory().getAbsolutePath()
Cursor cursor = MediaStore.Images.Media.query(
context.getContentResolver(),
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, STORE_IMAGES);
在 Android N 之前,内部文件可以通过放宽文件系统权限让其他应用访问。而如今不再是这种情况。如果您希望让其他应用访问私有文件的内容,则您的应用可使用FileProvider
使用作用域目录访问
在 Android 7.0 或更高版本中,如果您需要访问外部存储上的特定目录,请使用作用域目录访问。 作用域目录访问可简化您的应用访问标准外部存储目录(例如 Pictures 目录)的方式,并提供简单的权限 UI,清楚地详细介绍应用正在请求访问的目录。 有关作用域目录访问的更多详情,请参阅使用作用域目录访问
data/app
data/data/<package-name>/
1.data/data/包名/shared_prefs
2.data/data/包名/databases
3.data/data/包名/files
4.data/data/包名/cache
一般来说,在storage文件夹中有一个sdcard文件夹,这个文件夹中的文件又分为两类,一类是公有目录,还有一类是私有目录,其中的公有目录有九大类,比如DCIM、DOWNLOAD等这种系统为我们创建的文件夹,私有目录就是Android这个文件夹,这个文件夹打开之后里边有一个data文件夹,打开这个data文件夹,里边有许多包名组成的文件夹。
MOVIE PICTURE DCMI DOWNLOAD
/sdcard/Android/data/<package-name>/files
getExternalFileDir
/sdcard/Android/data/<package-name>/cache
getExternalCacheDir