一个File对象可用于读写大量的数据,比如,它可以用来保存图片和从网络获取到的数据。
选择内部(Internal)或外部(External)存储
所有的Android设备都有俩个文件存储位置,"内部(Internal)"和“外部(External)”。
Internal storage(内部存储)使用介绍:
- 一直存在,随时可以使用。
- 存储在此处的文件默认只能被你的App获取。
- 当用户卸载当前的App,系统将会删除当前App存储的所有文件。
如果你不想用户或者其他的App获取到你的文件,可以选择使用**Internal storage(内部存储)**去存储文件
#### 外部存储(External storage)使用介绍:
- 不是随时都能使用,因为如果用户移除外置的SD卡,或者USB连接等一些因素导致SD卡从设备上移除。
- 所有人都能从External storage中读取数据,所以数据存储到这里,不安全。
- 当用户卸载了你的App,系统只会清除掉**getExternalFilesDir()目录下的数据。
如果你想其他的App获取到你的数据,或者允许用户连接到电脑后读取数据,可以选择使用外部存储(External storage)**去存储。
小知识:应用默认都安装在internal storage,我们可以在manifest中配置android:installLocation来设置你的App安转在internal storage还是External Storage。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="preferExternal"
... >
目前来说,仅仅读取外部SD卡不需要加入任何权限,但是,在以后的版本中,谷歌表示会对此作出改变。所以谷歌建议,即使仅仅是读取外部SD卡,也加入READ_EXTERNAL_STORAGE,以免变动后受到影响。
但是,如果申明了WRITE_EXTERNAL_STORAGE,同时也获得了READ_EXTERNAL_STORAGE权限。
注意:如果你要使用internal storage存储文件,则不需要申明任何权限,直接使用即可。
存储文件到Internal Storage
可以通过俩个方法存储获取到Internal Storage的目录
**getFilesDir()**返回你的App的内部存储目录。
**getCacheDir()**返回你的App的内部缓存文件目录,在这个目录下数据,如果不需要了要及时的清楚,因为如果这个目录中的数据大于的1MB, 系统会自动清除里面的数据,而不会有任何提醒。
可以通过如下代码来创建一个文件在Internal Storage中
File file = new File(context.getFilesDir(), filename);
也可以调用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();
}
如果你需要缓存一些文件,可以用 **createTempFile()**方法。比如,下面的这个方法是从一个UR中抽取一个文件名称,并且创建文件在你的App所拥有的内部存储中。
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;
}
小结:
你的应用在Android硬盘中所占用的内部存储位置通常在你应用的包名目录下,如果你把文件Mode设置为readable,那么,另外的App也会访问到你的应用的内存存储文件,但是,其他的App需要知道你的应用的包名和文件名称,如果你不把文件权限设置为 readable 或者writable,其他的App默认是访问不到你的内部存储文件的。所以 ,只要你把内存储存中的文件模式设置为MODE_PRIVATE,其他App是不能获取到该文件的。
存储文件到External Storage
由于外部存储有时是不能使用的,所以在使用External Storage前,必须要判断是否可用。通常通过getExternalStorageState(). 来判断,如果返回的结果为MEDIA_MOUNTED,则你可以在External Storage中存储你的文件。以下是谷歌给出的判断External Storage是否可用的示例代码:
/* 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;
}
尽管外部存储的文件可以被用户或者其他的App操作,但是external storage的优势还是很明显的:
- external storage的文件可以被用户或其他App使用,当用户卸载了你的app,这些文件还是应该保留下来,比如,用过你的App拍的照片,或者下载的文件。
- 但你的App卸载的时候,一些属于你的App的数据应该被删除,尽管用户和其他App可以访问到这些数据,但是这些文件不用再为用户活其他App提供数据,所以,当用户下载App,所有在你App私有目录下的文件都会被删除。
如果你要在external storage上存储一个共享的文件,**getExternalStoragePublicDirectory() **可以获取到你的应用在external storage上的目录,这个方法中参数是为可说明你存储的文件的类型,以便于系统能够组织化的管理这些共享的数据,比如参数可以为DIRECTORY_MUSIC 或者DIRECTORY_PICTURES
,下面是谷歌给出我i示例代码:
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;
}
如果你想存储的数据是自己App私有,你可以通过**getExternalFilesDir()**方法获取,当你的App卸载的时候,还目录下的数据也会被删除。以下为谷歌提供的示例代码:
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(null),在参数里面传入null来获取到一你的App在external storage.中的私有根目录。
通过getExternalFilesDir()方法获取到目录,在用户卸载App时会被删除,如果你不想被删除,可以通过
getExternalStoragePublicDirectory().方法获取到的目录来存储数据。
无论你是通过 getExternalStoragePublicDirectory()方法还是getExternalFilesDir()方法来存数数据,目录名称还是非常重要的,谷歌建议使用API提供的常量目录名称,比如DIRECTORY_PICTURES。因为,这些目录下将会被系统分类进行管理,举例来说,如果你使用DIRECTORY_RINGTONES 目录,则系统将会把它分类到来电铃声的选择项中。
查询硬盘的可存储空间
如果你长时间的需要很多数据数据去存储,你可以通过
getFreeSpace() 或者 **getTotalSpace()**方法去查询可用空间的大小(如果存储空间不够,还在往磁盘中存数据,则抛出IOException),如果你的可用空间的少于90%,那么你就不能再在硬盘上存储数据了。
###删除文件
如果文件不需要了,你应该及时的删除,通常都是文件调用自己的delete() 方法来删除自己。
myFile.delete();
如果文件存储在internal storage,你也可以通过Context中的deleteFile()方法来删除文件。
myContext.deleteFile(fileName);
小结:
如果用户卸载了你的App,系统会删除以下文件:
- 你存储在internal storage上的所有文件。
- 你通过getExternalFilesDir()获取到external storage中的目录中的所有文件。
你应该去删除通过getCacheDir()获取到缓存文件和你不再需要的文件。