在Android中一共提供了5种数据存储方式,分别为:
(1)Files:通过FileInputStream和FileOutputStream对文件进行操作。
(2)Shared Preferences:常用来存储键值对形式的数据,对系统配置信息进行保存。
(3)Content Providers:数据共享,用于应用程序之间数据的访问。
(4)SQLite:Android自带的轻量级关系型数据库,支持SQL语言,用来存储大量的数据,并且能够对数据进行使用、更新、维护等操作。
(5)Network:通过网络来存储和获取数据。
本篇博文主要介绍第一种方式,通过文件存储数据。
在Android中,所创建的用于保存数据的文件可以位于两个位置:设备本身的存储空间中,或是外接的存储设备中(SD卡)。无论存储在哪个位置,在默认的情况下,该文件都是不能够供不同的应用程序共享的。
下面分别介绍如何将文件存储在设备本身的存储空间中以及外接的存储设备中。
1.将文件存储在设备本身的存储空间中
在Android中,可以使用Context类提供的以下两个方法来实现文件存储。
(1)public abstract FileInputStream openFileInput(String name);//打开文件输入流
(2)public abstract FileOutStream openFileOutput(String name, int mode);//打开文件输出流
其中,openFileInput()方法表示打开文件输入流,用于从文件中读取数据;openFileOutput()方法表示打开文件输出流,用于向文件中写入内容。
此外,openFileOutput()方法中的第二个参数mode用于指定文件的操作模式,其可选值有以下4种:
(1)Context.MODE_APPEND;//内容追加模式。在该模式下,系统会检查文件是否存在,如果存在,则将内容追加到文件的末尾,如果文件不存在,则创建该文件并写入内容。
(2)Context.MODE_PRIVATE;//默认操作模式。在该模式下,文件作为私有数据,只能被该应用程序本身访问。并且,在该模式下,写入的内容会覆盖原文件的内容。
(3)Context.MODE_WORLD_READABLE;//可读模式。在该模式下,别的应用程序可以读取该文件内容。
(4)Context.MODE_WORLD_WRITEABLE;//可写模式。在该模式下,别的应用程序可以将内容写入该文件。
1.1存储文件
一个简单的存储文件的例子如下:
1 /* 2 * Function : 保存文件到本地内存中 3 * Author : 博客园-依旧淡然 4 */ 5 public void saveContentToLocal(String fileNmae, String content) throws IOException { 6 FileOutputStream fileOutputStream = mContext.openFileOutput(fileNmae, Context.MODE_APPEND); 7 fileOutputStream.write(content.getBytes()); 8 if(fileOutputStream != null) { 9 fileOutputStream.close(); 10 } 11 }
以上的代码,通过将openFileOutput()的第二个参数设定为MODE_APPEND,指定了以内容追加模式存储文件。
1.2单体测试
如何来验证以上代码的正确性呢?我们可以通过创建单体测试来快速的对以上代码进行验证。
具体的单体测试代码如下:
1 /* 2 * Function : 单体测试保存文件到本地 3 * Author : 博客园-依旧淡然 4 */ 5 public void saveFileToLocal() throws IOException { 6 Context cotext = getContext(); 7 FileService fileService = new FileService(cotext); 8 fileService.saveContentToLocal("test.txt", "博客园-依旧淡然"); 9 }
通过运行该单体测试,我们在本地创建了一个名为“test.txt”的文本文件,其内容为“博客园-依旧淡然”。
该文件究竟被存放到了什么地方呢?其实,每安装一个应用程序,在data/data目录下都会产生一个文件夹,用来保存该应用程序的数据。如图1所示。
图1 Files方式存储数据到本地的文件目录
可见,该文件被存放到了目录data/data/com.example.android_datastorage_files/files下,其中com.example.android_datastorage_files是该工程的包名。导出该“test.txt”文本文件,打开可以看见其中内容确实是“博客园-依旧淡然”。
1.3读取文件
那么又该如何在程序中读取该文件呢?下面的代码给出了一种实现方案。
1 /* 2 * Function : 从本地内存中读取文件 3 * Author : 博客园-依旧淡然 4 */ 5 public String getFileFromLocal(String fileNmae) throws IOException { 6 7 FileInputStream fileInputStream = mContext.openFileInput(fileNmae); 8 9 //创建ByteArrayOutputStream对象,用于保存FileInputStream对象中的数据 10 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 11 12 //循环读写FileInputStream对象内容并保存到ByteArrayOutputStream对象中 13 int len = 0; 14 byte[] data = new byte[1024]; 15 while((len = fileInputStream.read(data)) != -1) { 16 byteArrayOutputStream.write(data, 0, len); 17 } 18 19 if(fileInputStream != null) { //关闭FileInputStream对象 20 fileInputStream.close(); 21 } 22 23 return new String(byteArrayOutputStream.toByteArray()); 24 }
同样的,我们可以创建一个单体测试来快速验证其正确性。具体方法和上一个单体测试类似,这里就不再赘述了。
2.将文件存储在外接存储设备中(SD卡)
通常,手机的内存是极其有限的,更普遍的做法是将文件存储到SD卡中。
将文件存储在外接存储设备中的方法和将文件存储在设备本身的存储空间中的方法类似,唯一的区别是每次向SD卡中存储以及从SD卡中读取文件时,都需要检测SD卡的状态。
2.1检测SD卡的状态
在Android中,检测SD卡的状态需要使用到Environment类。通过使用该类的getExternalStorageState()方法可以获得外接存储设备(SD卡)的状态。其中,外接存储设备的状态有九种,具体如图2所示。
其中,MEDIA_MOUNTED表示外接存储设备可读可写。
2.2存储文件
存储文件到SD卡中的一个简单例子如下:
1 /* 2 * Function : 保存文件到SD卡中 3 * Author : 博客园-依旧淡然 4 */ 5 public boolean saveContentToSDCard(String fileNmae, String content) throws IOException { 6 7 boolean isExternalStorageAvailable = false; //SD卡可读写的标志位 8 FileOutputStream fileOutputStream = null; //FileOutputStream对象 9 10 //创建File对象,以SD卡所在的路径作为文件存储路径 11 File file = new File(Environment.getExternalStorageDirectory(), fileNmae); 12 13 //判断SD卡是否可读写 14 if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { 15 isExternalStorageAvailable = true; 16 fileOutputStream = new FileOutputStream(file); //创建FileOutputStream对象 17 fileOutputStream.write(content.getBytes()); //向FileOutputStream对象中写入数据 18 if(fileOutputStream != null) { //关闭FileOutputStream对象 19 fileOutputStream.close(); 20 } 21 } 22 return isExternalStorageAvailable; 23 }
其中,Environment.getExternalStorageDirectory()方法用于获取SD卡所在的路径。在创建File对象时,指定其存储路径为SD卡所在的路径,既可以将文件存储到SD卡中。
2.3单体测试
同样地,我们创建一个单体测试来对以上的代码进行验证。
具体的单体测试代码如下:
1 /* 2 * Function : 单体测试保存文件到SD卡中 3 * Author : 博客园-依旧淡然 4 */ 5 public void saveFileToSDCard() throws IOException { 6 Context cotext = getContext(); 7 FileService fileService = new FileService(cotext); 8 boolean flag = fileService.saveContentToSDCard("hello.txt", "博客园-依旧淡然"); 9 Log.i(TAG, "flag-->"+flag); 10 }
通过运行该单体测试,我们可以在SD卡中创建了一个名为“hello.txt”的文本文件,其内容为“博客园-依旧淡然”。
那么,该文件又存储在什么地方呢?答案是mnt/sdcard目录下,如图3所示。
图3 Files方式存储数据到SD卡中的文件目录
2.4读取文件
从SD卡中读取文件与从本地内存中读取文件的方法大致相同,这里就不再赘述了。
有一点需要说明,因为程序中用到读写SD卡,所以需要在AndroidManifest.xml文件中加入向SD卡中写入数据的权限和在SD卡中创建和删除文件的权限。具体实现方法如下:
1 <!-- 向SD卡中写入数据的权限 --> 2 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 3 <!-- 在SD卡中创建和删除文件的权限 --> 4 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
3.实例(记事本)
了解了在Android中存储文件和读取文件的方法,我们可以实现一个简单的记事本应用程序。
通过使用该记事本可以输入文件的名字和内容,点击“保存文件”可以将文件内容保存到SD卡中,如图4所示。
图4 保存文件
当需要读取文件时,可以点击“读取文件”按钮。此时,会将文件内容从SD卡中的对应文件中读取并显示出来。如图5所示。
图5 读取文件
当然了,该实例只是提供了使用存储文件和读取文件的方法来实现记事本的一种思路,实例本身还有许多需要完善的地方。