来源: html
http://developer.android.com/training/basics/data-storage/files.html java
Android使用了一种相似于其它平台上基于磁盘文件系统的文件系统. 本节课描述了如何使用 File API在Android文件系统中读写文件. android
File 对象适用于用一种没有跳跃的从开始一直到结尾的方式读写大量数据. 例如,它很适合经过网络进行图片文件或者任何其它的文件交换. 缓存
本课程展现了如何在 你的应用中进行文件相关的基础操做. 本课程假定你熟悉Linux文件系统,还有java.io中的标准文件输入/输出操做. 安全
全部安卓设备都有两个存储区域: "内部" 和 "外部" 存储. 这些名称来自早期的安卓, 那时候大多数设备都提供内建的非易丢失内存 (内部存储), 再加上一个可移除的存储介质,好比微型SD卡 (外部存储). 一些设备将永久存储空间分红“内部”和“外部”分区, 所以即便没有可移除的存储介质,也总会两个存储空间,而无论外部存储是否是可移除的,API行为都是同样的. 下面的列表总结的每个存储空间的一些要点. 网络
内部存储: app
当你想要确保不论是你的用户仍是其它应用都能访问你的文件,内部存储是最合适的. ide
外部存储: ui
外部存储时保存那些不须要访问限制的文件的最好地方,还有那些你想要同其它应用共享或者容许用户使用计算机来访问的文件 . 编码
提示: 尽管应用默认被安装到内存存储, 其实你还能够在manifest中指定android:installLocation属性,那样你的应用就能够被安装在外部存储上了. 当APK的尺寸很是大,而且用户拥有一个比内存存储大得多的外部存储时,这一选择会受到欢迎. 更多的信息,能够看看 应用存储位置 .
为了写入外部存储,你必须在你的manifest文件处请求WRITE_EXTERNAL_STORAGE权限 :
<manifest ...> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ... </manifest>
注意: 当前,全部的应用都有能力不须要一个特定的权限就能够读取内部存储. 不过,这将会在未来的版本中改变. 若是你的应用须要读取内部存储(但不去写入它), 那么你将会须要声明 READ_EXTERNAL_STORAGE 权限. 为了确保你的应用能如预期的运做, 在变化尚未起做用以前,你如今就应该声明这一权限.
<manifest ...> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> ... </manifest>
不过,若是你的应用使用了 WRITE_EXTERNAL_STORAGE 权限,那么它也就隐含了读取内部存储的权限了 .
在内部存储上保存文件不须要任何权限. 你的应用程序老是有在其内部存储目录中读写文件的权限.
当要在一个内部存储中保存一个文件时,你能够经过调用下面两个方法的其中之一,来获取相应的目录 文件 :
getFilesDir()
返回一个表示你应用的内部路径的 File .
返回一个表示你应用的临时缓存内部路径的 File . 要确保一旦文件再也不须要时都删除一次,而且在任何给定时间你使用的内存都有一个合理的大小限制, 好比 1MB. 若是系统开始低存储消耗的运行 , 他可能在没有提示就删除了你的缓存文件.
为了在这些目录中的一个里面建立一个新的文件,你可使用 File() 构造器,传入由上述指定了你的内部存储路径的方法提供的 File . 例如:
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(). 例如,下面的方法能够获取名称来自一个 URL 的文件,并使用这个名称在你的应用的内部缓存路径中建立一个文件 :
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_PRIVATE , 它们就不再会被其它应用访问到了.
因为外部存储可能不可用——好比用户已经将其挂载到了一台PC上,或者已经将提供外部存储的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() 方法来获取一个表示外部存储上对应文件的 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; }
若是你想要保存为你应用所私有的文件,你能够经过调用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() 并传入null. 这回返回外部存储上你的应用的私有路径的根路径 .
请记住当用户卸载你的应用时,getExternalFilesDir() 在一个路径中建立的路径都会被删除掉 . 若是你想要存储的文件在用户卸载你的应用后还能用 — 诸如当你的应用是一个照相机,而用户想要保留这些照片时 — 你应该换用 getExternalStoragePublicDirectory().
无论你是使用文件能够被共享的 getExternalStoragePublicDirectory() 或者文件为你的应用所私有的 getExternalFilesDir() , 你所使用的由API提供像DIRECTORY_PICTURES这样的常量都很重要 . 这些路径名称确保了文件为系统正常对待 . 例如,存储在 DIRECTORY_RINGTONES 中的文件能够被系统的媒体搜索器归为铃声一类,而不是音乐 .
若是你事先知道要保存多少数据,你就能够经过调用 getFreeSpace() 或者 getTotalSpace() 发现是否有足够空间保存这些数据,而不会致使一个 IOException . 这些方法分别提供了存储卷中当前有多少可用空间以及总空间. 这种信息在避免填充的数据量超过必定的阈值时也一样有用 .
不过,系统并不能确保你能够写入同 getFreeSpace() 所获取到的剩余空间大小同等量的数据. 若是返回的数量比你想要保存的数据多几个MB,或者若是文件系统占率低于90%,那么每每还算安全。不然,你可能就不该该再往里面写入了.
注意: 你并不必定要在保存你的文件以前检查剩余空间的数量. 你能够尝试首先写入文件,而后获取一个 IOException ,若是这个异常发生了的话 . 若是你并不知道你须要多少空间的时候,可能就得这么作 . 例如,若是你在保存文件以前改变了文件的编码方式,将一张PNG图片转换成了JPG的,你是不会事先知道文件的大小的 .
你应该老是删除你再也不须要的文件。删除一个文件最直接的方式是让打开的文件引用自身调用 delete() .
myFile.delete();
若是文件被保存在外部存储上,你也能够经过调用deleteFile()叫 Context来定位并删除一个文件 :
myContext.deleteFile(fileName);
注意: 当用户卸载你的应用时,Android系统会删除下面这些东西 :
不过,你应该按期手动的去删除使用 getCacheDir() 建立的缓存文件,也要有规律的去删除你再也不须要的文件.