Android使用的文件系统和其他平台的基本磁盘的文件系统很相似。这里将要介绍如何使用File API在Android文件系统中读写文件。

File对象适合按顺序读写大量的数据。例如,适合图片文件或者其他在网络上交换的东西。

这里将要展示基本的文件相关的任务。这里假设你熟悉基本的Linux文件系统和标准的java.io中的输入输出。

选择内部或外部存储

所有的Android设备由两种存储位置:内部存储和外部存储。这些名字来源于早期的Android,大多数提供内置的不可拆解的存储器(internal storage),加上一个可移除的存储介质比如micro SD 卡(external storage)。有些设备把永久存储空间分为“内部”和“外部”,就算没有可移除的存储介质,总有两个存储空间不管外部存储是否存在API的行为是一样的。下面列出了两种存储空间的简介。

内部存储:

  • 总是可用的

  • 这里存储的文件默认是只能被你的app访问到。

  • 当用户卸载了app,系统会把app所有的文件从内部存储上删除。

当你要确保无论是用户还是其他app都不能访问你的文件时,内部存储是最好的地方

外部存储:

  • 不总是可用的,因为用户可能会把外部存储当作USB使用或者有时候会从设备上拿走。

  • 谁都可以读,这里保存的文件可以总是被读,不在你的控制之中。

  • 当用户卸载你的app时,系统只会删除getExternalFilesDir()文件夹中的文件。

如果文件没有访问权限,或者你向和其他app分享,或者可以让用户通过电脑访问,外部存储是最好的地方。

提示:虽然app是默认安装到内部存储上,但是你一个指定manifest中的android:installLocation让app了以安装到外部存储上。当APK很大或者外部存储大小比内部存储大小大时,用户很喜欢这个选择。更多信息,查看App Install Location

申请外部存储权限

要在外部存储上写入,必须在manifest中申请WRITE_EXTERNAL_STORAGE权限:

 <manifest ...>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
</manifest>

注意:目前,不需要特殊权限,所有的app都有读外部存储的权限。但是,这个在未来的版本中可能会改变。如果app需要读外部存储(但是不需要写),你需要申明READ_EXTERNAL_STORAGE权。为了确保app按照预期的工作,在未来的版本修改之前,现在就要声明这个权限。

 <manifest ...>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
...
</manifest>

但是,如果app使用的WRITE_EXTERNAL_STORAGE权限,隐藏的就也拥有了读取外部存储的权限。

在内部存储上保存文件不需要任何权限。你的程序在它的内部存储文件夹下一直都有读写文件的权限。

在内部存储上保存文件

当在内部存储上保存文件时,你可以通过File的下面两个方法获获得文件夹:

getFilesDir()

返回一个File,代表app的内部文件夹

getCacheDir()

返回一个File,代表app的临时cache文件的内部文件夹。确保在文件不需要的时候删除它们,并且在任何时候要限制使用的内存在一个合理的大小,比如1MB。当系统运行到存储不够时,可能不提示警告就会删除你的cache。

要在这些文件夹中创建一个新文件,你可以使用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中抽取文件名,然后用那个文件名在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;
}

注意:app的内部文件夹是由app的包名在Android文件系统的一个特殊位置指定的。技术上来说,其他app可以读取你的内部文件如果你设置文件模式为可读。但是,其他app需要知道你的app的包名和文件名。其他app不能浏览你的内部文件夹也不能读写除非你明确的设置文件为可读或可写。所以只要你在内部存储时文件使用MODE_PRIVATE模式,其他app就一直不能进入它们。

在外部存储上保存文件

由于外部存储可能不可用(比如用户把存储安装到了PC或者拿走了提供外部存储的SD卡),每次进入之前都要检查是否可用。可以通过getExternalStorageState()来查询外部存储状态。如果返回的状态是MEDIA_MOUNTED,那么可以读写文件。例如,下面的方法可以判断存储是否可用:

 /* 查看外部存储是否可读可写 */
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;
}

虽然外部存储可以被用户和其他app修改,你可以在这里存储两类文件:

公有文件

可被其他app和用户自由使用的文件。当用户卸载app后,这些文件仍然可以被用户使用。

比如:你的app获取的照片,或者下载的文件。

私有文件

属于你的app的并且卸载时需要删除的文件。虽然因为是在外部存储上这些文件技术上来说是可以被用户和其他app进入的,但是这些文件对于你的app之外的用户没有任何实际意义。当用户卸载app时,系统会删除app外部存储文件夹下的所有文件。

比如:app另外下载的资源或者临时媒体文件。

如果需要在外部存储中保存公有文件,使用getExternalStoragePublicDirectory()方法来获得代表外部存储上的适合的文件夹的File。这个方法带有一个指定你要保存的文件类型的参数,这样可以在逻辑上和其他公有文件进行管理,比如DIRECTORY_MUSIC或者DIRECTORY_PICTURES。例:

 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;
}

如果要保存app的私有文件,可以调用getExternalFilesDir()然后传递一个你喜欢的表示文件夹类型的名字来获得合适的文件夹。每个这样创建的文件夹会被加到一个父文件夹中,父文件夹包含了你的app的所有外部存储文件,它们会在用户卸载app时被系统删除。

例如,这里的方法可以用来创建一个私有的相册文件夹:

 public File getAlbumStorageDir(Context context, String albumName) {
// 获得app私有图片文件夹.
File file = new File(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}

如果还没有合适你文件的预定好的子文件名字,可以调用getExternalFilesDir()时传递一个null参数。这样会返回app在外部存储中私有文件夹的根文件夹。

记住getExternalFilesDir()是在一个用户卸载app后会删除的文件夹中创建的文件夹。如果你保存的文件是要在用户删除app后仍然保留的(比如你的app是一个相机 ,用户想要保留这些照片),你应该使用getExternalStoragePublicDirectory()。

不管是为可分享的文件使用getExternalStoragePublicDirectory()还是为app私有文件使用getExternalFilesDir(),使用API常量比如DIRECTORY_PICTURES作为文件夹名很重要。这些文件夹名确保了系统会合适的处理这些文件。例如,DIRECTORY_RINGTONES中的文件会被系统认为是铃声而不是音乐。

查询可用空间

如果提早知道保存了多少数据,可以知道是否有充足的空间可用,不会通过调用getFreeSpace()getTotalSpace()导致一个IOException。这些方法分别可以提供存储卷轴上当前的可用空间个总空间。这些信息对于避免存储超过存储极限很有用。

然而,系统并不保证你可以写getFreeSpace()指示的那么多的字节。如果返回的数字比要存储的数据大几MB,或者文件系统存储量小于90%,那么存储会很安全。否则,可能不能向存储中写入。

注意:不需要在存储文件时查看可用空间,可以在try中写文件,然后catch IOException如果出现异常。当不知道需要多大空间时也可以这么做。例如,在存储之前把文件编码从PNG转换成JPEG,预先是不知道文件大小的。

删除文件

不在需要的文件要删除。最直接的删除文件的方式是调用已打开文件自己的delete()

 myFile.delete();

如果文件保存在内部存储上,也可以用Context来定位然后调用deleteFile()来删除文件:

 myContext.deleteFile(fileName);

注意:当用户卸载app时,Android系统会删除下面的文件:

  • 所有保存在内部存储上的文件

  • 所有使用getExternalFilesDir()保存在外部存储上的文件。

但是,应该按照基本规则手动删除用getCacheDir()创建的缓存文件,和其他不再需要的文件。

上一篇:Android - 数据存储 -存储键值对

下一篇:Android - 数据存储 -在SQL数据库中保存数据

Android - 数据存储 -存储文件的更多相关文章

  1. Android - 数据存储 -存储键值对

    如果你有少量的键值数据需要存储,可以使用SharedPreferencesAPI.SharedPreferences对象指向一个包含键值对的文件并且提供了一些简单的方法来读取它们.每个SharedPr ...

  2. Android数据存储之SQLCipher数据库加密

    前言: 最近研究了Android Sqlite数据库(文章地址:Android数据存储之Sqlite的介绍及使用)以及ContentProvider程序间数据共享(Android探索之ContentP ...

  3. Android数据存储之GreenDao 3.0 详解

    前言: 今天一大早收到GreenDao 3.0 正式发布的消息,自从2014年接触GreenDao至今,项目中一直使用GreenDao框架处理数据库操作,本人使用数据库路线 Sqlite----> ...

  4. Android数据存储方式--SharedPreferences

    Android数据存储方式有如下四种:SharedPreferences.存储到文件.SQLite数据库.内容提供者(Content provider).存储到网络服务器. 本文主要介绍一下Share ...

  5. Android数据存储-通过SharedPreferences实现记住密码的操作

    在Android中登陆中,为了实现用户的方便,往往需要根据用户的需要进行记住密码的操作,所以,在Android数据存储中SharedPreferences恰恰可以实现这一点 下面,小编将带领大家通过S ...

  6. 10、Android数据存储

    课程目标: 掌握Android中数据存储的几种方式 熟练使用PreferenceActivity&PreferenceScreen做专业的Setting功能 熟练使用SQLite3来存储数据 ...

  7. Android数据存储五种方式

    1 使用SharedPreferences存储数据:常用于做本地缓存 2 文件存储数据:(1)data/data/<package name>/files目录内   (2)SDCard内 ...

  8. Android数据存储:SDCard

    Android数据存储之SDCard 0.获取sd卡路径. 1.讲述 Environment 类. 2.讲述 StatFs 类. 3.完整例子读取 SDCard 内存 0.获取sd卡路径 方法一: p ...

  9. Android数据存储:SQLite

    Android数据存储之SQLite SQLite:Android提供的一个标准的数据库,支持SQL语句.用来处理数据量较大的数据.△ SQLite特征:1.轻量性2.独立性3.隔离性4.跨平台性5. ...

随机推荐

  1. redis做RDB时请求超时case

        近期在排查redis做rdb时会有部分请求超时的case.初步推断是我们redisserver上开启了THP(Transparent Huge Pages).      1) Linux本身的 ...

  2. Codeforces 196 C. Paint Tree

    分治.选最左上的点分给根.剩下的极角排序后递归 C. Paint Tree time limit per test 2 seconds memory limit per test 256 megaby ...

  3. html练习(5)

    这个练习主要简单的展示了据对定位和相对定位: 在此说下html的定位: 1.static定位 这个是默认的方式.对static而言.left和right是不生效的. 2.relative定位(相对定位 ...

  4. ssh, maven and eclipse 那些破事

    Unix根据该理念keep it simple, keep it stupid.可在j2ee有keep it complex, keep it smart. 所以,我彻底晕菜. 最后能活着把sprin ...

  5. POJ 2151 Check the difficulty of problems (动态规划-可能DP)

    Check the difficulty of problems Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4522   ...

  6. 在ireport中使用checkbox

    在网上搜索了很多实现checkbox的办法, 主要是利用打钩图片实现. 下面是我的做法,也不怎么高明, 不过比利用图片好. 后台 map.put("lifeTimePartFlag" ...

  7. XmlDocument.Load()加载xml文件时,提示分析 EntityName 时出错的问题。

    今天一个接口突然报错,错误是: 分析 EntityName 时出错. 行 35,位置 90. xmlDoc.Load(System.Web.HttpContext.Current.Server.Map ...

  8. xcode Workspaces

    A workspace is an Xcode document that groups projects and other documents so you can work on them to ...

  9. Windown安装Mysql安装图解

    一.MYSQL的安装 1.打开下载的mysql安装文件mysql-5.0.27-win32.zip,双击解压缩,运行“setup.exe”. 2.选择安装类型,有“Typical(默认)”.“Comp ...

  10. JAVA邮件收发实现(待)

    http://blog.csdn.net/ycg01/article/details/1394465