File
对象适合顺序不跳过地读取和写入大量数据。例如,图片文件或通过网络交换的任何内容。
存储区域
Android设备有两个文件存储区域:“内部”和“外部”存储。早期设备“内部存储”指的是内置存储,而“外部存储”指的是外置可拆卸的移动存储,比如SD卡。现在基本上没有外置移动存储,而依然将存储区域划分为这两部分。
内部存储
- 始终可用
- 只有你的应用可以访问这里保存的文件
- 用户卸载应用时候,会删除应用在这里存放的文件
不希望用户或其他应用访问的那些文件信息,可以放到这里。
外部存储
- 并非始终可用。用户可采用USB存储设备的形式装载外部存储,并且可拆卸
- 全局可读。因此这里存放的文件可以不受你的控制被读取。
- 当用户卸载应用时候,系统会卸载你存放在通过调用
getExternalFilesDir()
获取的目录里的文件。
外部存储适用于存放那些无需访问限制,以及你希望共享给其他应用或允许用户使用电脑访问的文件。
应用默认安装在内部存储中,可以修改应用清单文件中的android:installLocation
属性来指定默认安装位置。
获取访问外部存储的权限
当前应用默认具有外部存储读取权限,而写权限必须申请。后续版本可能会要求申请外部存储区域读权限。
获取外部存储写权限,隐含外部区域读权限,反之不成立。
获取写权限
...
获取读权限
...
应用始终具有读写内部存储区域的权限,无需申请。
保存文件到内部存储
内部应用存储空间根目录通常是/data/data/
获取缓存目录的方法(Context
类提供):
-
getFilesDir()
:返回应用内部存放文件的目录的绝对路径。一般就是/data/data/
。这个目录也是调用/files openFileOutput
方法创建的文件的目录。 -
getCacheDir()
:返回应用内部存储的临时目录。通常是/data/data/
。当系统内部存储即将耗尽的时候,可能会删除这个目录下的文件。/cache -
getDir()
:方法getDir(String name, int mode)
包含两个参数,可用于在应用内部存储根目录下创建或打开自定义的文件目录。name
表示自定义的文件目录名。mode
表示操作模式,用来控制该目录的读写权限,默认为MODE_PRIVATE
,表示仅仅应用自身可以访问。MODE_WORLD_READABLE
允许其他应用读取你创建的文件,不安全,已经不建议使用。MODE_WORLD_WRITEABLE
允许其他应用读写你的文件,不安全,不建议使用。
在目录下创建文件,File的构造参数中传入目录和文件名,例如
File file = new File(context.getFilesDir(), filename);
或者,调用openFileOutput()
方法获取写入到getFilesDir()
目录的FileOutputStream
。比如,在getFilesDir()
目录下写入一个名为myfile.txt
的文件,内容为Hello world!
:
String filename = "myfile.txt";
String string = "Hello world!";
FileOutputStream outputStream;
try {
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(string.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
保存文件到外部存储
外部存储可能不可用,比如用户将其挂载到了电脑或者移除了提供外部存储的SD卡,因此,在访问之前,需要先确认其可用。
调用getExternalStorageState()
方法查询外部存储状态,如果返回为MEDIA_MOUNTED
,表示可用,这时你可以对其进行读写。
检查外部磁盘是否可用于读写操作:
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
/* Checks if external storage is available to at least read */
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()
方法获取,需要指定文件类型参数,以便外部统一处理。比如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;
}
应用卸载时,系统不会删除这些文件。
私有文件目录获取
调用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;
}
上述方法会在Environment.DIRECTORY_PICTURES
目录下创建albumName
值的目录,当然你也可以将第一个参数传为null,则会在你应用外部存储私有目录的根目录下创建。
查询可用空间
File
类的getFreeSpace()
和getTotalSpace()
返回当前目录下可用空间和总的空间大小。
但是,系统并不保证你能够写入getFreeSpace()
大小的数据。如果可用空间大小比你要保存的数据多几MB,或者文件系统剩余空间大小超过10%,你多半是可以安全写入。否则的话,你可能不应该写入存储。
写入之前也可以不检查磁盘可用量,可以尝试写入,然后在
IOException
发生时捕获。
删除文件
记住,文件不用了就及早删除。删除文件的方法:
File.delete()
如果文件保存在内部存储中,还可以调用Context.deleteFile(fileName)
来定位和删除文件。
注:当用户卸载您的应用时,Android 系统会删除以下各项:
- 保存在内部存储中的所有文件
- 使用
getExternalFilesDir()
保存在外部存储中的所有文件。