作为android新手,前一段写个程序,想缓存一些数据到android设备中,不知往哪里存,通过查资料总结了一下,以便加深记忆和以后查询,如果不正确的地方,欢迎指出。

一、首先说一下android的存储类型,分为内部存储和外部存储。

内部存储。

内部存储是指手机内置的存储空间。内部存储空间有限,它也是系统本身和系统应用程序主要的数据存储所在地,一旦内部存储空间耗尽,手机也就无法使用了。

    Android本身是一个Linux操作系统,所以它的内部存储空间,对于应用程序和用户来讲就是“/data/data"目录。它与外部存储相比,比较稳定,更加安全(因为可以控制访问权限)等优点。而它的缺点就是空间有限。

虽然,可以非常容易的知道程序本身的数据所在路径,所有的应用程序的数据路径都是“/data/data/your-package-name/”,所有的程序用到的数据,比如libs库,SharedPreferences都是存放在这个路径下面。但我们在使用的时候最好不要直接引用这个路径(例如,直接通过绝对路径访问android中的文件,在卸载应用时,可能不会自动删除该文件)。 应该通过Context类提高的函数来操作文件,使用Context不但操作简单方便,最重要的是Context会帮助我们管理这些文件,也可以方便帮助我们控制文件的访问权限。

另外,对于内部存储还有一个非常重要的特点,那就是在应用程序被卸载时,应用程序在内部存储空间的目录或子文件夹下的所有文件将会被删除。

   (2)、外部存储。

外部存储是指出厂的时候不存在,用户在使用时候可以自由添加的外部存储介质比如TS卡,SD卡等闪存储介质。

    优点:存储空间大,基本上你可无限制的使用。

    缺点:

  • 与内部存储不同的是,当程序卸载时,它在外部存储所创建的文件数据是不会被清除的,所以清理外部存储空间的责任丢给了用户自己;
  • 在外部存储介质上存储文件时,这里的文件没有强制的安全保障。任何的应用程序都可以访问、重写或者删除这些文件。存储在外部存储中的文件可能不是总是可用的,使用之前要判断是否可用。android通过一下方法检测外部存储是否可用:
String status = Environment.getExternalStorageState();
if (status.equals(Environment.MEDIA_MOUNTED)) {
	// 外部存储可用
}

二、其次说一下应用程序文件的存储位置。应用程序私有和公共可读。

   (1)、私有:针对于特定应用程序的文件夹。又分三种常用的情况。

  1. 第一种情况:特定于应用程序的文件夹(是目录而非文件):创建或获得指定目录,可以在该目录下创建自己的文件夹。
    android上下文Context提供了两种相应的方法:getDir() 和 getExternalFilesDir()。这两个方法都返回一个File对象,每个对象会包含有指向内部(/data/data/Your Package Name/app_"name参数的值",文件名字系统默认会添加一个前缀“app_”)或外部的应用程序文件存储目录的路径。
    先看getDir方法的代码:

    第一个参数为存储目录的名称,指定希望存放文件的子目录。name名字可以自己定义。

    再看getExternalFilesDir(该方法是从Android 2.2版本引入的,如果需要支持更早的版本,可以调用Environment.getExternalStorageDirectory()方法来返回一个外部存储的根路径),该方法有一个参数,如果传递null,则会得到应用程序的外部存储目录的files子目录(模拟器为:/mnt/sdcard/Android/data/Your Package Name/files,'/mnt/sdcard'为sdcard的跟目录,具体设备的值可能不一样,可以根据Environment.getExternalStorageDirectory()查询当前设备的sdcard的根目录)。如果传入其他则会在“/mnt/sdcard/Android/data/Your Package Name/files”目录下创建相应的文件夹,可以参考Environment类的一些DIRECTORY_[Categrory]字符串常量,作为参数:
• DIRECTORY_ALARMS:系统提醒铃声存放的标准目录
• DIRECTORY_DCIM: 相机拍摄照片和视频的标准目录
• DIRECTORY_DOWNLOADS: 下载的文件标准目录
• DIRECTORY_MOVIES:  电影存放的标准目录
• DIRECTORY_MUSIC : 音乐存放的标准目录
• DIRECTORY_NOTIFICATIONS: 系统通知铃声存放的标准目录
• DIRECTORY_PICTURES: 图片存放的标准目录
• DIRECTORY_PODCASTS :系统广播存放的标准目录
• DIRECTORY_RINGTONES: 系统铃声存放的标准目录
  • 即使使用了DIRECTORY_[Categrory]字符串常量,因为是应用程序私有的,所以这些文件不会被自动添加到媒体库中,如果想要这些文件对其他应用程序也可用,可以参考后面的“公共可读”部分。
  1. 第二种情况:是第一种情况的简化方式,目录的名字固定为“files”(即路径为/data//data/Your Package Name/files),而且android提供了简易的方法来操作该目录下的文件。以下为这些简易方法:Context.getFilesDir():Your Package Name/files目录的File对象(根据名字可以看出目录为“files”)。Context.openFileInput()与Context.openFileOutput():     只能读取和写入files目录(完整路径:/data/data/Your Package Name/files)的文件,返回的是FileInputStream和FileOutputStream对象。   在创建FileOutputStream时,如果指定的文件名不存在,android会自动创建。对于已经存在的文件默认行为为覆盖它;如     果想要在文件末尾添加内容,可以指定气模式为Context.MODE_APPEND。    默认情况下,使用openFileOutput方法创建的文件对于调用应用程序是私有的,其他应用程序会被拒绝访问。在不同应用程序 之间共享文件的标准方式是通过ContentProvider。另外,当创建输出文件时,可以通过Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE让它在其他应用程序中也可用。Context.fileList():    返回files下所有的文件名,返回的是String[]对象。
Context.deleteFile(String):

  1.     删除files下指定名称的文件。
  2. 第三种情况:目录的名字固定为“cache”(即路径为/data/data/Your Package Name/cache),但是用来缓存临时文件。
    如果应用程序需要缓存临时文件,Android提供了一个可管理的内部缓存和一个不能管理的外部缓存。分别调用了getCacheDir和getExternalCacheDir方法可以从Context中访问它们。
    存储在任何一个该缓存位置中的文件在应用程序被卸载之后都会被删除。当系统运行在低可用空间的时候,存储在内部缓存中的文件可能会被系统删除;存储在外部缓存中的文件则不会被删除,因为系统不会跟踪外部媒介的可以存储空间。

(2)、公共可读。

Environment.getExternalStoragePublicDirectory(),可以用来找到外部存储中存储应用程序文件的路径。返回的位置为用户通常存放或管理他们自己的各种类型的文件的位置。这对于那些提供功能来代替或扩充系统应用程序的应用程序尤其有用,它在标准的位置存储文件,这些文件是公共可读的。

    getExternalStoragePublicDirectory()方法接受一个字符串常量,即前面写到的Environment的那些静态常量,来确定想要访问的子目录。注意,如果返回的目录不存在,必须在向该目录写入文件前先创建它。

最后,参考一下http://biancheng.dnbcw.info/shouji/427664.html中的例子代码,看一下上面提到的这些方法的目录绝对路径,记得加上读写sdcard的权限(     

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>):/*
		 * 1.创建并返回一个指定名称的目录,在这个目录下来存些东西 输出结果为:
		 *   getDir():/data/data/com.example.filedemo/app_abc
		 */
		File dir1 = getDir("abc", MODE_PRIVATE);
		Log.i("MainActivity", "getDir():" + dir1.toString());
		
		/*
		 * 2.创建并返回一个目录,在这个目录下存储应用程序的数据文件 输出结果为:
		 *   getFilesDir():/data/data/com.example.filedemo/files
		 */
		File dir2 = getFilesDir();
		Log.i("MainActivity", "getFilesDir():" + dir2.toString());
		
		/*
		 * 3.打开一个输出流对象,通过这个输出流对象可以向abc.txt文件中写入一些数据,
		 * abc.txt文件位于/data/data/com.example.filedemo/files下;
		 */
		try {
			FileOutputStream out = openFileOutput("abc.txt", MODE_PRIVATE);
			out.write("hello world".getBytes());
			out.flush();
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		/*
		 * 4.获取一个输入流对象,通过这个输入流对对象读取指定文件,这个文件在/data/data/com.example.filedemo/files下;
		 */
		try {
			FileInputStream is = openFileInput("abc.txt");
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			int len = 0;
			byte[] buf = new byte[4];
			while ((len = is.read(buf)) > 0) {
				out.write(buf, 0, len);
				out.flush();
			}
			out.close();
			is.close();
			Log.i("MainActivity", "openFileInput()读取到的数据:"+out.toString());
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		/*
		 * 5.获取 /data/data/com.example.filedemo/files文件夹下面的所有的文件名字。
		 */
		String[] fileList = fileList();
		for (String string : fileList) {
			Log.i("MainActivity", "fileList():" + string);
		}

		/*
		 * 6.删除 /data/data/com.example.filedemo/files文件夹下面某个文件。
		 * 重新执行一下第3条的代码,换个文件名,测试deleteFile()函数。
		 */
		try {
			FileOutputStream out = openFileOutput("abc2.txt", MODE_PRIVATE);
			out.write("hello world".getBytes());
			out.flush();
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		// 删除刚才创建的文件
		deleteFile("abc2.txt");
		
		/*
		 * 7.创建并返回一个目录,在这个目录下存储应用程序的缓冲文件,当系统资源不足时,系统清除这下面的文件
		 * 输出结果为:getCacheDir():/data/data/com.example.filedemo/cache
		 */
		File dir3 = getCacheDir();
		Log.i("MainActivity", "getCacheDir():" + dir3.toString());

		/*
		 * 8.返回sdcard的状态,每次使用sdcard时,都会检查其状态; 
		 * 输出结果是:status=mounted
		 */
		String status = Environment.getExternalStorageState();
		Log.i("MainActivity", "Environment.getExternalStorageState():" + status);
		
		/*
		 * 9.创建并返回外部存储文件目录,需要sd卡的的写入数据权限;
		 * 输出结果是:getExternalFilesDir():/mnt/sdcard/Android/data/com.example.filedemo/files/Music
		 */
		if (status.equals(Environment.MEDIA_MOUNTED)) {
			File dir4 = getExternalFilesDir(Environment.DIRECTORY_MUSIC);
			Log.i("MainActivity", "getExternalFilesDir():" + dir4.toString());
		} 

		/*
		 * 10.创建并返回外部存储缓冲目录,需要sd卡的写入数据权限;
		 * 输出结果是:getExternalCacheDir():/mnt/sdcard/Android/data/com.example.filedemo/cache
		 */
		if (status.equals(Environment.MEDIA_MOUNTED)) {
			File dir5 = getExternalCacheDir();
			Log.i("MainActivity", "getExternalCacheDir():" + dir5.toString());
		} 
		
		/*
		 * 11. 获取内部存储的数据目录 
		 *   输出结果是:Environment.getDataDirectory():/data
		 */
		File dir6 = Environment.getDataDirectory();
		Log.i("MainActivity", "Environment.getDataDirectory():" + dir6.toString());

		/*
		 * 12.获取内部存储下载缓冲目录,隐藏的目录;
		 *  输出结果为:Environment.getDownloadCacheDirectory():/cache
		 */
		File dir7 = Environment.getDownloadCacheDirectory();
		Log.i("MainActivity", "Environment.getDownloadCacheDirectory():" + dir7.toString());

		/*
		 * 13.获取内部下载系统的根目录,
		 *  输出结果为:Environment.getRootDirectory():/system
		 */
		File dir8 = Environment.getRootDirectory();
		Log.i("MainActivity", " Environment.getRootDirectory():" + dir8.toString());

		/*
		 * 14.返回sdcard的根目录;
		 * 输出结果为:Environment.getExternalStorageDirectory():/mnt/sdcard
		 */
		File dir9 = Environment.getExternalStorageDirectory();
		Log.i("MainActivity", "Environment.getExternalStorageDirectory():" + dir9.toString());

		/*
		 * 15.返回sdcard公共存储目录; 结果:getExternalStoragePublicDirectory():/mnt/sdcard/Music
		 */
		File dir10 = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
		Log.i("MainActivity", "getExternalStoragePublicDirectory():" + dir10.toString());
		
		/*
		 * 16.用于返回数据库中指定名字的文件路径,在内部存储中应该保存的路径;
		 * 输出结果为:getDatabasePath():/data/data/com.example.filedemo/databases/stu.db
		 */
		File dir11 = getDatabasePath("stu.db");
		Log.i("MainActivity", "getDatabasePath():" + dir11.toString());

输出结果: 
 
getDir():/data/data/com.example.filedemo/app_abc
 getFilesDir():/data/data/com.example.filedemo/files
 openFileInput()读取到的数据:hello world
 fileList():abc.txt
 getCacheDir():/data/data/com.example.filedemo/cache
 Environment.getExternalStorageState():mounted
 getExternalFilesDir():/mnt/sdcard/Android/data/com.example.filedemo/files/Music
 getExternalCacheDir():/mnt/sdcard/Android/data/com.example.filedemo/cache
 Environment.getDataDirectory():/data
 Environment.getDownloadCacheDirectory():/cache
 Environment.getRootDirectory():/system
 Environment.getExternalStorageDirectory():/mnt/sdcard
 getExternalStoragePublicDirectory():/mnt/sdcard/Music
 getDatabasePath():/data/data/com.example.filedemo/databases/stu.db
各个设备的有些路径可能会不相同,以下是我的华为P6的测试结果:
 getDir():/data/data/com.example.filedemo/app_abc
 getFilesDir():/data/data/com.example.filedemo/files
 openFileInput()读取到的数据:hello world
 fileList():abc.txt
 getCacheDir():/data/data/com.example.filedemo/cache
 Environment.getExternalStorageState():mounted
 getExternalFilesDir():/storage/emulated/0/Android/data/com.example.filedemo/files/Music
 getExternalCacheDir():/storage/emulated/0/Android/data/com.example.filedemo/cache
 Environment.getDataDirectory():/data
 Environment.getDownloadCacheDirectory():/cache
 Environment.getRootDirectory():/system
 Environment.getExternalStorageDirectory():/storage/emulated/0
 getExternalStoragePublicDirectory():/storage/emulated/0/Music
 getDatabasePath():/data/data/com.example.filedemo/databases/stu.db


参考书籍:《Android 4 高级编程》

参考网址:

http://ipjmc.iteye.com/blog/1447097 http://my.eoe.cn/887769/archive/5566.html

http://biancheng.dnbcw.info/shouji/427664.html

http://www.xuebuyuan.com/912689.html