文件存儲
Android 提供了很多種存儲的數(shù)據(jù)的方式,比如“Shared Preferenced”、“文件”、“SQLite”、“遠(yuǎn)端”等等。其中最直接的就是文件存儲,本節(jié)就來看看如果通過文件的方式持久化我們的數(shù)據(jù)。
1. 文件存儲的特點
文件存儲是最好理解的一種方式,類似“新建文件夾”然后“創(chuàng)建文件”,最后直接把數(shù)據(jù)寫到對應(yīng)文件中即可??紤]到文件的安全性,Android 為每個 App 都分配了一個私有文件讀取權(quán)限,也就是每個 App 創(chuàng)建的私有文件只有自己的 App 才有權(quán)限訪問,就極大的保護(hù)了用戶的隱私安全。
2. 文件存儲的相關(guān)方法
文件操作基本上就是做文件 I/O,圍繞輸入輸出主要提供了以下方法:
- openFileInput(String fileName):
打開文件輸入流,獲取文件中的信息 - openFileOutput(String fileName, int mode):
以某種模式打開文件輸出流,將信息輸出到文件中 - getDir(String fileName, int mode):
創(chuàng)建或者獲?。ㄈQ于是否存在)文件名為 fileName 的文件,并存儲在 App 的私有目錄(data目錄)下 - getFileDir():
獲取 App 私有目錄(data目錄)文件對應(yīng)的絕對路徑 - deleteFile(String fileName):
不必多解釋,刪除目錄 - String[] fileList():
獲取目錄下的全部文件,返回全部文件列表
3. 文件 I/O 操作
3.1 文件輸出
通過調(diào)用openFileOutput()
來獲取一個文件輸出流,然后將數(shù)據(jù)寫入輸出流從而最終保存到對應(yīng)的文件中。在第 2 小節(jié)提到過,openFileOutput()
有一個 mode 參數(shù),它可以設(shè)置成
MODE_PRIVATE
:私有文件,僅支持當(dāng)前 App 訪問MODE_WORLD_READABLE
:除了當(dāng)前 App,僅支持可讀權(quán)限MODE_WORLD_WRITEABLE
:其他 App 可寫MODE_APPEND
:文件內(nèi)容追加,默認(rèn)是會覆蓋
該方法返回一個文件輸出流實例,之后便可以通過輸入流實例來向文件寫數(shù)據(jù)了,代碼示例如下:
FileOutputStream out = openFileOutput("file name here",MODE_WORLD_READABLE);
String str = "data";
out.write(str.getBytes());
out.close();
3.2 文件輸入
通過openFileInput()
可以讀取我們剛剛創(chuàng)建的文件,和FileOutputStream
方法類似,該方法返回一個輸入流,接著我們可以從輸入流里讀取數(shù)據(jù),代碼示例如下:
FileInputStream in = openFileInput(file);
int c;
String temp="";
// 挨個讀取字符
while( (c = in.read()) != -1){
temp = temp + Character.toString((char)c);
}
// temp就是從文件中讀取的內(nèi)容
in.close();
4. 文件讀取示例
前面提到過,對于文件的操作主要就是輸入和輸出,所以我們就圍繞這兩個操作來做一個示例。下面一起編寫一段代碼,通過輸入一段字符串然后保存到文件中,后續(xù)可以任意殺掉進(jìn)程退出 App,再點擊“讀取”即可獲取到前面輸入的字符串內(nèi)容,完成一個文件的保存和讀取。
4.1 布局文件
首先我們來編寫布局文件,核心內(nèi)容很簡單,主要有四個元素:
- 輸入框: 接收需要保存的數(shù)據(jù)
- 數(shù)據(jù)文本: 展示從文件中讀取的數(shù)據(jù)
- 保存/加載: 點擊觸發(fā)數(shù)據(jù)的輸入和輸入
布局代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="30dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="文件存儲"
android:textSize="35sp" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/title"
android:layout_centerHorizontal="true"
android:text="慕課Android教程"
android:textColor="#ff7aff24"
android:textSize="35sp" />
<Button
android:id="@+id/save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@+id/textView"
android:layout_alignParentBottom="true"
android:text="保存" />
<EditText
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/imageView"
android:layout_centerHorizontal="true"
android:layout_marginTop="42dp"
android:hint="輸入要保存的內(nèi)容"
android:textColorHighlight="#ff7eff15"
android:textColorHint="#ffff25e6" />
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/textView"
android:layout_centerHorizontal="true"
android:src="@mipmap/ic_launcher" />
<Button
android:id="@+id/load"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/save"
android:layout_alignEnd="@+id/editText"
android:text="加載文件" />
<TextView
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/editText"
android:layout_centerHorizontal="true"
android:textColor="#ff5bff1f"
android:textSize="25sp" />
</RelativeLayout>
4.2 I/O 邏輯編寫
我們在 MainActivity 中給幾個核心元素增加事件處理,其中兩個 Button 的 onClick 事件就分別對應(yīng)這文件的“輸入”、“輸出”操作,代碼如下:
package com.emercy.myapplication;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
public class MainActivity extends Activity {
Button save, load;
TextView content;
EditText input;
String data;
private String file = "MC_data";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
save = findViewById(R.id.save);
load = findViewById(R.id.load);
input = findViewById(R.id.editText);
content = findViewById(R.id.content);
save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
data = input.getText().toString();
try {
FileOutputStream fOut = openFileOutput(file, MODE_WORLD_READABLE);
fOut.write(data.getBytes(StandardCharsets.UTF_8));
fOut.close();
Toast.makeText(getBaseContext(), "文件保存成功", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
});
load.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
FileInputStream fin = openFileInput(file);
byte[] buf = new byte[1024];
int count;
StringBuilder temp = new StringBuilder();
while ((count = fin.read(buf)) > 0) {
temp.append(new String(buf, 0, count, StandardCharsets.UTF_8));
}
content.setText(temp.toString());
Toast.makeText(getBaseContext(), "文件加載成功", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
save 的 onCilck 事件里的就是文件輸出,比較簡單;而 load 里面的 onClick 事件所做的事就是文件輸入,這里有一段核心代碼我們單獨看看:
FileInputStream fin = openFileInput(file);
byte[] buf = new byte[1024];
int count;
StringBuilder temp = new StringBuilder();
while ((count = fin.read(buf)) > 0) {
temp.append(new String(buf, 0, count, StandardCharsets.UTF_8));
}
這里我們先創(chuàng)建一個大數(shù)據(jù)——buf[1024],然后調(diào)用“inputStream”的read(buf)
方法,此方法會盡可能的從輸入流中讀取數(shù)據(jù)到 buf 數(shù)組中,并返回真實讀取的數(shù)據(jù)。此時判斷讀取的數(shù)據(jù)是否大于0,如果不大于 0 則表示文件已到末尾,就可以跳出循環(huán)結(jié)束讀取。
編譯之后,在文本輸入框輸入任意字符,之后可以殺進(jìn)程、關(guān)手機等等操作,再次進(jìn)入 App,點擊“加載”依然可讀取到之前輸入的內(nèi)容。效果如下:
5. 小結(jié)
本節(jié)講述了一種 Android 數(shù)據(jù)持久化最直接的方式,我們通過openFileOutput
打開一個文件輸出流,然后往輸出流里 write 數(shù)據(jù),就可以在 SD 卡上創(chuàng)建一個文件;而后通過openFileInput
打開一個文件輸入流,接著從輸入流里拿到文件內(nèi)容就可以還原原始數(shù)據(jù),完成一個數(shù)據(jù)的持久化操作