資料儲存方式:
對比sql資料庫唄
1.檔案儲存
方式同java中I/O輸入輸出流一樣
舉個例子:
public class 位元組流_寫文字檔案 {
public static void main(String[] args) throws IOException {
/**位元組流建立文字檔案。在D盤SS目錄中建立students.txt檔案,並新增以下資訊:
* 姓名:張三,性別:男,年齡:19,成績:90,入學日期:2022-9-10
* 姓名:李四,性別:女,年齡:19,成績:95,入學日期:2022-9-9
*/
String str="姓名:張三,性別:男,年齡:19,成績:90,入學日期:2022-9-10 " +
"姓名:李四,性別:女,年齡:19,成績:95,入學日期:2022-9-9";
OutputStream fileOutputStream = new FileOutputStream("D:\\SS\\students.txt");
//OutputStream是所有輸出流的父類,為一個抽象類
byte[] bytes = str.getBytes(); // getBytes()將字串轉換為位元組陣列
for (int i = 0; i < bytes.length; i++) {
fileOutputStream.write(bytes[i]);
}
fileOutputStream.close(); //關閉輸出流並釋放與其關聯的所有系統資源
}
}
public class 位元組流_讀文字檔案 {
public static void main(String[] args) throws IOException {
InputStream fileInputStream = new FileInputStream("D:\\SS\\students.txt");
byte[] bytes =new byte[170];
int b;
while ((b=fileInputStream.read(bytes))!=1){
System.out.println(new String(bytes,0,b));
//將指定byte陣列中從起始索引off開始的len位元組寫入輸出流
// b={'1' ,'2', '3', '4', '5', '6', '7', '8'};
// String item=new String(b,2,2)
// 結果 item=34
}
fileInputStream.close();
}
}
來看看Android中的:
首先分為內部儲存和外部儲存
:外部儲存就是SD卡之類的 屬於永久性的儲存方式 但不安全
三項:
獲取SD卡的狀態
判斷是否可用
獲取SD卡路徑
String state = Environment.getExternalStorageState();
state.equals(Environment.MEDIA_MOUNTED);
Environment.getExternalStorageDirectory();
然後再透過輸入輸出流寫入讀取就行
注意注意:申請SD卡寫讀檔案的許可權 要在清單檔案中靜態申請許可權
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
主要來看看內部儲存:
透過一個案例模擬qq登入:
layout佈局就不寫了
我沒寫trycatch這樣是不對的 沒有處理異常
但主要是為了驗證
package com.example.store;
import android.content.Context;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
//工具類 實現QQ的賬號密碼儲存和讀取
public class Tool_qqAcitivity {
public static boolean saveUser(Context context, String user, String pwd) throws IOException {
FileOutputStream fos = context.openFileOutput("haha.txt", Context.MODE_PRIVATE);
//將資料轉換為位元組碼的形式寫入haha.txt中
fos.write((user + ":" + pwd).getBytes());
fos.close();
return true;
}
public static Map<String, String> getUser(Context context) throws IOException {
String str = "";
FileInputStream fis = context.openFileInput("haha.txt");
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
str = new String(buffer);
HashMap<String, String> map = new HashMap<String, String>();
String[] split = str.split(":");
if (split.length >= 2) {
map.put("user", split[0]);
map.put("pwd", split[1]);
} else {
// 處理錯誤情況,例如檔案內容格式不正確或為空
// 可以選擇丟擲異常、記錄日誌或返回null等
// 這裡只是簡單地返回一個空的map
return new HashMap<>();
}
fis.close();
return map;
}
}
package com.example.store;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import java.util.Map;
public class QQ_Activity extends AppCompatActivity {
//初始化
private EditText et_account;
private EditText et_password;
private Button btn_login;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qq);
et_account = findViewById(R.id.et_account);
et_password = findViewById(R.id.et_password);
btn_login = findViewById(R.id.btn_login);
try {
Map<String, String> user = Tool_qqAcitivity.getUser(this);
if(user!=null){
et_account.setText(user.get("user"));
et_password.setText(user.get("pwd"));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String user = et_account.getText().toString().trim();
String pwd = et_password.getText().toString();
//檢查是否為空
if(TextUtils.isEmpty(user)){
Toast.makeText(QQ_Activity.this, "請輸入賬號", Toast.LENGTH_SHORT).show();
return;
}
if(TextUtils.isEmpty(pwd)){
Toast.makeText(QQ_Activity.this, "請輸入密碼", Toast.LENGTH_SHORT).show();
return;
}
Toast.makeText(QQ_Activity.this, "登入成功", Toast.LENGTH_SHORT).show();
//儲存使用者資訊 呼叫工具
try {
boolean b = Tool_qqAcitivity.saveUser(QQ_Activity.this, user, pwd);
if(b){
Toast.makeText(QQ_Activity.this, "儲存成功", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(QQ_Activity.this, "儲存失敗", Toast.LENGTH_SHORT).show();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
}
}
需要注意的就是:
內部儲存 當建立的應用程式被解除安裝時 內部儲存檔案也隨之刪除
許可權引數:
MODE_PRIVATE 只能被當前程式讀寫
MODE_APPEND 內容可以追加
MODE_WORLD_READABLE 內容可被其他程式讀
MODE_WORLD_WRITEABLE 內容可被其他程式寫
2.SharedPreferences儲存
一個輕量級儲存類
獲取例項物件
SharedPreferences 名字 = getSharedPreferences("名字", MODE_PRIVATE);
獲取編輯器
透過鍵值對形式儲存(put方法)在data/data/包名/shared_prefs中的XML中
SharedPreferences.Editor edit = 名字.edit();
edit.putString("key","value");
edit.commit();
讀取資料
名字.getString("key","不存在返回這個");
移除資料
edit.remove("key");
edit.clear();
3.SQLite資料庫儲存
這個就有意思了 是Android自帶的一個小型資料庫
儲存的檔案在這裡:
參考:https://blog.csdn.net/hjjshua/article/details/124150812
直接透過例子來看:
還是跳過layout佈局檔案
package com.example.store;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
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 androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import org.w3c.dom.Text;
//在Activity中編寫 與前面傳遞過來的屬性 進行操作
public class SimpleDataActivity extends AppCompatActivity implements View.OnClickListener {
//資料初始化
MyHelper helper;
private EditText et_id;
private EditText et_name;
private EditText et_age;
private Button btn_add;
private Button btn_query;
private Button btn_update;
private Button btn_delete;
//用來展示結果
private TextView tv_show;
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple);
//呼叫自己繼承SQLiteOpenHelper的MyHelper
helper = new MyHelper(this);
et_id = findViewById(R.id.et_id);
et_name = findViewById(R.id.et_name);
et_age = findViewById(R.id.et_age);
btn_add = findViewById(R.id.btn_add);
btn_query = findViewById(R.id.btn_query);
btn_update = findViewById(R.id.btn_update);
btn_delete = findViewById(R.id.btn_delete);
tv_show = findViewById(R.id.tv_show);
//第三種方法別忘記寫這個
btn_add.setOnClickListener(this);
btn_query.setOnClickListener(this);
btn_update.setOnClickListener(this);
btn_delete.setOnClickListener(this);
}
//使用第三種方法繼承介面實現方法 按鈕點選後的改變 增刪改查也在這裡實現
/*
ContentValues類 它負責儲存一些名值對
它儲存的名值對當中的名是一個String型別 而值都是基本型別
*/
@Override
public void onClick(View v) {
String id, name, age;
SQLiteDatabase db;
ContentValues values;
//Google寫好的增刪改查api
if (v.getId() == R.id.btn_add) {
//增
//獲取輸入框的值
id = et_id.getText().toString();
name = et_name.getText().toString();
age = et_age.getText().toString();
//獲取可讀寫的SQLiteDatabase物件
db = helper.getWritableDatabase();
//建立ContentValues物件
values = new ContentValues();
values.put("id", id);
values.put("name", name);
values.put("age", age);
//三個引數 1.資料表名字 2.如果發現將要插入的行為空行 列名設為null 3.ContentValues物件
db.insert("gao", null, values);
Toast.makeText(this, "資訊也新增", Toast.LENGTH_SHORT).show();
//當使用完SQLiteDatabase物件後呼叫close方法關閉資料庫連線 否則資料庫一直存在 消耗記憶體
db.close();
}
//查
if (v.getId() == R.id.btn_query) {
//獲取可讀的SQLiteDatabase物件
db = helper.getReadableDatabase();
//Cursor是一個遊標介面 提供了便利查詢結果的方法
Cursor cursor = db.query("gao", null, null, null, null, null, null);
//判斷下是否有資料
//兩種Cursor物件的遍歷方法
//第一種先輸出第一個值 再移動遊標
if (cursor.getCount() == 0) {
Toast.makeText(this, "無資料", Toast.LENGTH_SHORT).show();
} else {
cursor.moveToNext();
tv_show.append("id:" + cursor.getString(0) + " name:" + cursor.getString(1) + " age" + cursor.getString(2));
}
while (cursor.moveToNext()) {
tv_show.append("\n" + "id:" + cursor.getString(0) + " name:" + cursor.getString(1) + " age" + cursor.getString(2));
}
//第二種先移動遊標 再輸出第一個值
// if(cursor.getCount()>0){
// while (cursor.moveToNext()) {
// tv_show.append("id:" + cursor.getString(0) + " name:" + cursor.getString(1) + " age" + cursor.getString(2));
// }
// }else {
// Toast.makeText(this, "無資料", Toast.LENGTH_SHORT).show();
// }
//用完Cursor 要關閉 否則造成記憶體洩漏
cursor.close();
db.close();
}
//修
if (v.getId() == R.id.btn_update) {
db = helper.getWritableDatabase();
values = new ContentValues();
values.put("name",name=et_name.getText().toString());
values.put("age",name=et_age.getText().toString());
// 資料表名字 最新資料 要修改資料的查詢條件 查詢條件的引數
db.update("gao",values,"id=?",new String[]{
et_id.getText().toString()
});
Toast.makeText(this,"資訊已修改",Toast.LENGTH_SHORT).show();
db.close();
}
//刪
if (v.getId() == R.id.btn_delete) {
db = helper.getWritableDatabase();
db.delete("gao",null,null);
Toast.makeText(this,"資訊已刪除",Toast.LENGTH_SHORT).show();
db.close();
}
}
//資料庫和表的建立
class MyHelper extends SQLiteOpenHelper {
public MyHelper(Context context) {
//四個引數 上下文 資料庫名字 遊標工廠 資料庫版本
super(context, "gao.db", null, 2);
}
// 建立表
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table gao(id int primary key,name varchar,age int)");
}
//資料庫版本號增加時呼叫
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
}
總結一下這個:
大致裡面寫的註釋也夠清楚了
其中兩種Cursor物件的遍歷方法
參考 https://blog.csdn.net/qq_64628470/article/details/129974041
當然還有其他資料儲存方式
也對應著Android四大元件之一的內容提供者和觀察者