Android存储空间
做过Android开发的都知道,Android将文件空间分为两部分,一部分是外部空间,一部分是内部空间。
内部空间
内部空间有以下特征:
- 它始终可用。
- 默认情况下只有您的应用可以访问此处保存的文件。
- 当用户卸载您的应用时,系统会从内部存储中删除您的应用的所有文件。
当我们希望我们应用的数据不能被其他应用访问时,我们可以选择内部空间。
由于每个应用都拥有自己的内部空间,所以当我们在内部空间上操作时,是不需要任何权限的。
外部空间
而外部空间有以下特征:
- 它并非始终可用,因为用户可采用 USB 存储的形式装载外部存储,并在某些情况下会从设备中将其删除。
- 它是全局可读的,因此此处保存的文件可能不受您控制地被读取。
- 当用户卸载您的应用时,只有在您通过 getExternalFilesDir() 将您的应用的文件保存在目录中时,系统才会从此处删除您的应用的文件
外部空间是全局可见的,所有的应用都可以对其进行操作,所以当我们需要共享数据的时候,我们可以采用外部空间。
和内部空间不同,外部空间的操作需要我们申请权限,
android.permission.WRITE_EXTERNAL_STORAGE,用来向外部空间进行写操作,
android.permission.READ_EXTERNAL_STORAGE,用来向外部空间进行读操作。
需要提醒的是,当我们的应用拥有了外部空间写权限后,它也默认拥有了读权限。
如何使用内部空间
我们可以使用getFilesDir()方法来得到内部空间的绝对地址,getCacheDir()方法用来得到内部空间缓存区绝对地址。getFilesDir()返回的绝对路径为/data/data/your pkgname/files/
getCacheDir()返回的绝对路径为/data/data/your pkgname/cache/
获得内部空间地址后,我们可以新建一个文件。
File file = new File(context.getFilesDir(), filename);
得到文件的File实力后,我们可以使用Java的标准I/O来对文件进行读写。
或者我们可以通过 openFileOutput() 方法来得到目标文件的FileOutputStream,示例代码如下,
String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;
try {
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(string.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
如何使用外部空间
外部空间的使用相比较内部空间来说,比较类似,只不过我们首先要申请权限,然后为了可靠性,在使用外部空间之前,判断是否加载成功,
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;
}
外部空间也分为公共文件和私有文件。
公共文件
应供其他应用和用户自由使用的文件。 当用户卸载您的应用时,用户应仍可以使用这些文件。
例如,您的应用拍摄的照片或其他已下载的文件。
私有文件
本属于您的应用且应在用户卸载您的应用时删除的文件。尽管这些文件在技术上可被用户和其他应用访问(因为它们在外部存储上),它们是实际上不向您的应用之外的用户提供值的文件。当用户卸载您的应用时,系统会删除应用外部专用目录中的所有文件。
例如,您的应用下载的其他资源或临时介质文件。
如果您要使用外部存储上的公共文件,可以使用 getExternalStoragePublicDirectory() 方法获取表示外部存储上相应目录的 File 。该方法使用指定 您想要保存以便它们可以与其他公共文件在逻辑上组织在一起的文件类型的参数,比如 DIRECTORY_MUSIC 或 DIRECTORY_PICTURES。 例如:
public File getAlbumStorageDir(String albumName) {
// Get the directory for the user's public pictures directory.
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}
上述代码返回的是Pictures的目录,在nexus 5x上的绝对路径是/storage/emulated/0/Pictures
或者如果我们保存的是其他类型文件,我们可以直接使用绝对路径来进行文件访问。
如果您要保存您的应用专用文件,您可以通过调用 getExternalFilesDir() 获取相应的目录并向其传递指示您想要的目录类型的名称。 通过这种方法创建的各个目录将添加至封装您的应用的所有外部存储文件的父目录,当用户卸载您的应用时,系统会删除这些文件。
例如,您可以使用以下方法来创建个人相册的目录:
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;
}
getExternalFilesDir(fileName)返回的文件路径是 /storage/emulated/0/Android/data/your pkgname/files/fileName
如果没有适合您文件的预定义子目录名称,您可以改为调用 getExternalFilesDir() 并传递 null。这将返回外部存储上您的应用的专用目录的根目录,路径为/storage/emulated/0/Android/data/your pkgname/files