GitHub地址:
https://github.com/Skymqq/FileSave.git
数据持久化就是指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或电脑关机的情况下,这些数据仍然不会丢失。保存在内存中的数据是处于瞬时状态的,而保存在存储设备中的数据是处于持久状态的,持久化技术则提供了一种机制可以让数据在瞬时状态和持久状态之间进行转换。
Android系统中主要提供了3中方式用于简单地实现数据持久化功能:
1.文件存储
2.SharedPreferences存储
3.数据库存储
除了以上3中方式之外,你还可以将数据保存在SD卡中,不过使用文件、SharedPreferences或数据库来保存数据会相对简单一些,而且也比SD存储更安全。
文件存储
文件存储是Android中最基本的一种数据存储方式,它不对存储的内容进行任何的格式化处理,所有的数据都是原封不动地保存到文件当中的,因而它比较适合存储一些简单的文本数据或二进制数据。如果你想使用文件存储的方式来保存一些较为复杂的文本数据,就需要定义一套自己的格式规范,这样可以方便之后将数据从文件中重新解析出来。
那么我们就来看一下,Android中是如何通过文件来保存数据的。
将数据存储到文件中:
Context类中提供了一个openFileOutput()方法,可以用于将数据存储到指定的文件中。这个方法接收两个参数,第一个是文件名,在文件创建的时候使用的就是这个名称,注意这里指定的文件名不可以包含路径,因为所有的文件都是默认存储到/data/data/<packagename>/files/目录下的。第二个参数是文件的操作模式,主要有两种模式可选,MODE_PRIVATE和MODE_APPEND。其中其中MODE_PRIVATE是默认的操作模式,表示当指定同样文件名的时候,所写入的内容将会覆盖原文件中的内容,而MODE_APPEND则表示如果该文件已存在,就往文件里面追加内容,不存在就创建新文件。
openFileOutput()方法返回的是一个FileOutputStream对象,得到了这个对象之后,就可以使用Java流的方式将数据写入到文件中了。
下面我就简单地写个demo来实现一下最基本的文件存储。
首先布局文件里放入一个EditText控件和Buttton控件,EditText控件用于输入需要保留的数据,Button控件用于响应点击监听。
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">
<EditText
android:id="@+id/et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:hint="请输入需要保存到文件的数据"
android:textSize="18sp" />
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="save"
android:textAllCaps="false"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout>
MainActivity.java代码:
package com.example.administrator.filesave;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class MainActivity extends AppCompatActivity {
private EditText et;
private Button btn;
private FileOutputStream out;
private BufferedWriter writer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
et = (EditText) findViewById(R.id.et);
btn = (Button) findViewById(R.id.btn);
}
@Override
protected void onResume() {
super.onResume();
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
save();//存储数据到文件
}
});
}
private void save() {
try {
out = openFileOutput("data", MODE_PRIVATE);//初始化FileOutput对象
writer = new BufferedWriter(new OutputStreamWriter(out));//初始化BufferedWriter(带缓存的字符输出流)
try {
writer.write(et.getText().toString());//将EditText控件中的数据写入输出流。
Toast.makeText(this, "file already saved", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();//关闭输出流
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
自定义save()方法用来保存数据到文件,我们只需要在Button的点击监听事件中调用save()方法就可以了。
效果图:
最后,我们怎么才能看到数据已经存入到本地文件中了呢?光看这Toast提示,显然是不可取的。
这个文件的具体路径为data/data/<com.example.administrator.filesave>/files/data,首先我们得打开Device File Explorer
然后找data文件,再找一个data文件,最后找到带我们项目包名的文件,下面有个files文件夹,最后有一个data文件,打开data文件,你可以直接看到我们写入的deal friend数据,效果图如下所示:
如果你是一个足够细心的同学,在你多次输入数据之后,会发现数据只会一直被新增的数据所覆盖,原因就是我们在MainActivity.java文件中的save()方法中,为FileOutput对象初始化的时候,构造函数传参的第一个参数是“data”文件名,第二个参数为MODE_PRIVATE,这个操作模式是默认的操作模式,表示当指定同样文件名的时候,所写入的内容将会覆盖源文件中的内容,如果希望数据追加,那么只需要将操作模式设置为MODE_APPEND即可。
在MainActivity活动被销毁的时候将瞬时数据保存到文件:
这个功能就很简单了,只需要重写onDestroy()方法,然后在这里面调用save()方法就可以了。
@Override
protected void onDestroy() {
super.onDestroy();
save();//保存瞬时数据到文件
}
从文件中读取数据:
上面我们实现了将数据保存到本地文件的功能,现在我们再实现一个从文件中读取数据的功能。
上面我们在MainActivity活动被销毁之后,将数据保存到本地文件中,那么我们能否在下此打开程序的时候,直接再将数据从文件中读取并显示在EditText控件中呢?显然是可以的。
类似于将数据存储到文件中,Context类中还提供了一个openFileInput()方法,用于从文件中读取数据。这个方法要比openFileOutput()简单一些,它只接收一个参数,即要读取的文件名,然后系统会自动到data/data/<package name>/files/目录下去加载这个文件,并返回一个FileInputStream对象,得到了这个对象之后再通过java流的方式就可以将数据读取出来了。
MainActivity.java代码:
package com.example.administrator.filesave;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class MainActivity extends AppCompatActivity {
private EditText et;
private Button btn;
private FileOutputStream out;
private BufferedWriter writer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();//初始化控件
initData();//初始化数据
}
private void initView() {
et = (EditText) findViewById(R.id.et);
btn = (Button) findViewById(R.id.btn);
}
private void initData() {
et.setText("" + load());
}
@Override
protected void onResume() {
super.onResume();
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
save();//存储数据到文件
}
});
}
private void save() {
try {
out = openFileOutput("data", MODE_PRIVATE);//初始化FileOutput对象
writer = new BufferedWriter(new OutputStreamWriter(out));//初始化BufferedWriter(带缓存的字符输出流)
try {
writer.write(et.getText().toString());//将EditText控件中的数据写入输出流。
Toast.makeText(this, "file already saved", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();//关闭输出流
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private String load() {
FileInputStream in = null;
BufferedReader reader = null;
StringBuilder content = new StringBuilder();
try {
in = openFileInput("data");
reader = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = reader.readLine()) != null) {
content.append(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return content.toString();
}
@Override
protected void onDestroy() {
super.onDestroy();
save();//保存瞬时数据到文件
}
}
在这段代码中,首先通过openFileInput()方法获取到了一个FileInputStream对象,然后借助它又构建出一个BufferedReader(带缓存的字符输入流)对象,这样我们就可以通过BufferedReader进行一行行地读取,把文件中所有的文本内容全部读取拼接出来,并存放在一个StringBuilder对象中,最后将读取到的内容返回就可以了。
效果图:
输入“听妈妈的话”,这个应该属于瞬时数据,然后我们退出程序即MainActivity活动被销毁,此时根据Activity的生命周期,系统会调用onDestroy()方法,然后再去调用save()方法保留数据。
再次打开程序,我们发现数据已经从文件中读取出来,并且显示到EditText控件上了。