Android学习之文件存储
•前言
任何一个应用程序,其实说白了就是在不停地和数据打交道,我们聊QQ、看新闻、刷微博,所关心的都是里面的数据,
没有数据的应用程序就变成了一个空壳子,对用户来说没有任何实际用途。
那么这些数据都是从哪来的呢?
现在多数的数据基本都是由用户产生的,比如你发微博、评论新闻,其实都是在产生数据。
什么是瞬时数据呢?
就是指那些存储在内存当中,有可能会因为程序关闭或其他原因导致内存被回收而丢失的数据。
这对于一些关键性的数据信息来说是绝对不能容忍的,谁都不希望自己刚发出去的一条微博,刷新一下就没了吧。
那么怎样才能保证一些关键性的数据不会丢失呢?这就需要用到数据持久化技术了。
•持久化技术简介
数据持久化就是指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或电脑关机的情况下,这些数据仍然不会丢失。
保存在内存中的数据是处于瞬时状态的,而保存在存储设备中的数据是处于持久状态的,
持久化技术则提供了一种机制可以让数据在瞬时状态和持久状态之间进行转换。
Android系统中主要提供了 3种 方式用于简单地实现数据持久化功能,即文件存储、SharedPreference存储以及数据库存储。
•文件存储
文件存储是 Android 中最基本的一种数据存储方式,它不对存储的内容进行任何的格式化处理,
所有数据都是原封不动地保存到文件当中的,因而它比较适合用于存储一些简单的文本数据或二进制数据。
如果你想使用文件存储的方式来保存一些较为复杂的文本数据,就需要定义一套自己的格式规范,这样可以方便之后将数据从文件中重新解析出来。
那么首先我们就来看一看,Android 中是如何通过文件来保存数据的。
•将数据存储到文件中
在学习本次内容前,你要先学会 Java 中的 IO 流,鄙人不才,写了一篇关于 IO 流的博客,毛遂自荐一下🔗;
接下来,创建一个 TestFilePersistence 项目,并修改 activity_main.xml 中的代码;
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="10dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="现在是瞬时数据" android:textSize="20sp" /> <EditText android:id="@+id/edit" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="type something here" /> </LinearLayout>这里在布局中加入了一个 EditText,用于输入文本内容。
现在运行一下程序了,界面上有一个文本输入框,然后在文本输入框中随意输入点什么内容,按下 Back 键,在打开,
这时输人的内容肯定就已经丢失了,因为它只是瞬时数据,在活动被销毁后就会被回收。
运行效果
而这里我们要做的,就是在数据被回收之前,将它存储到文件当中。
Context类中提供了一个 openFileOutput() 方法,可以用于将数据存储到指定的文件中。
这个方法接收两个参数:
第一个参数是文件名,在文件创建的时候使用的就是这个名称
- 注意这里指定的文件名不可以包含路径
- 因为所有的文件都是默认存储到 /data/data/<package name>/files/ 目录下的
第二个参数是文件的操作模式,主要有两种模式可选
- MODE_PRIVATE 和 MODEAPPEND
- 其中 MODEPRIVATE 是默认的操作模式,表示当指定同样文件名的时候所写入的内容将会覆盖原文件中的内容
- 而 MODEAPPEND 则表示如果该文件已存在,就往文件里面追加内容,不存在就创建新文件
其实文件的操作模式本来还有另外两种:
- MODE_WORLD_READABLE 和 MODE_WORLD_WRITEABLE
- 这两种模式表示允许其他的应用程序对我们程序中的文件进行读写操作
- 不过由于这两种模式过于危险,很容易引起应用的安全性漏洞,已在Android4.2版本中被废弃
openFileOutput() 方法返回的是一个 FileOutputStream 对象,得到了这个对象之后就可以使用 Java流 的方式将数据写入到文件中了。
接下来通过代码做个简单示例。
修改 MainActivity.java 中的代码;
MainActivity.java
public class MainActivity extends AppCompatActivity { private EditText edit; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); edit = findViewById(R.id.edit); } @Override protected void onDestroy() { super.onDestroy(); try { save(getData()); } catch (IOException e) { e.printStackTrace(); } } public String getData(){ return edit == null ? null:edit.getText().toString(); } public void save(String data) throws IOException{ //IO流常规操作 FileOutputStream out = openFileOutput("data.txt",Context.MODE_PRIVATE); out.write(data.getBytes()); out.close(); } }可以看到,首先我们在 onCreate() 方法中获取了 EditText 的实例,然后重写了 onDestroy() 方法,
这样就可以保证在活动销毁之前一定会调用这个方法。
在 onDestroy() 方法中调用 save() 方法把输入的内容存储到文件中,文件命名为data。
现在重新运行一下程序,并在 EditText 中输入一些内容;
然后按下 Back键 关闭程序,这时我们输入的内容就已经保存到文件中了。
那么如何才能证实数据确实已经保存成功了呢?我们可以借助 Android Device Monitor 工具来查看一下。
Android Device Monitor
点击上方工具栏中的【Tools】,并在下拉菜单中选择【SDK Manager】;
再弹出的界面中找到【Android SDK】;
右侧会出现【Android SDK】的存储路径,找到该路径所表示的文件;
依次点击【tools】->【lib】->【monitor-x86_64】;
在弹出的界面中双击【monitor.exe】
这个就是 Android Device Monitor;
找到 Android Device Monitor 工具后,进入 File Explorer 标签页,在这里找到
data/data/com.example.testfilepersistence/files
目录,可以看到,在该目录中生成了一个 data.txt 文件;
选中该文件,并点击右上角红框框处的按钮,将该文件导出到电脑上,并查看该文件的内容;
这样就证实了,在 EditText 中输入的内容确实已经成功保存到文件中了。
不过只是成功将数据保存下来还不够,我们还需要想办法在下次启动程序的时候让这些数据能够还原到EditText中,
因此接下来我们就要学习一下如何从文件中读取数据。
•从文件中读取数据
类似于将数据存储到文件中,Context 类中还提供了一个 openFileInput() 方法,用于从文件中读取数据。
这个方法要比 openFile0utput() 简单一些,它只接收一个参数,即要读取的文件名,
然后系统会自动到 /data/data/<package name>/files/ 目录下去加载这个文件,并返回一个FileInputStream对象,
得到了这个对象之后再通过 Java流 的方式就可以将数据读取出来了。
修改 MainActivity.java 中的代码;
MainActivity.java
public class MainActivity extends AppCompatActivity { private EditText edit; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); edit = findViewById(R.id.edit); try { String s = read(); edit.setText(s); edit.setSelection(s.length());//将输入光标移动到文档末尾 Toast.makeText(this,"读取成功",Toast.LENGTH_SHORT).show(); } catch (IOException e) { e.printStackTrace(); } } @Override protected void onDestroy() {...} public String getData(){...} public void save(String data) throws IOException{...} public String read() throws IOException{ FileInputStream in = openFileInput("data.txt"); byte[] b = new byte[100]; String s = ""; int x = 0; while((x = in.read(b)) != -1){ s += new String(b,0,x); } return s; } }在 read() 方法中,首先通过 openFileInput() 方法获取到了一个 FileInputStream 对象,
我们就可以通过 FileInputStream 进行读取,把文件中所有的文本内容全部读取出来,并存放在一个 String 对象中;
最后将读取到的内容返回就可以了。
运行结果