輕量級資料持久化 (帳號、Token、設定) 不想用 SharedPreferences 或 SQLite 時,直接讀寫內部儲存檔案是不二之選。Context.getFilesDir() 提供的私有目錄,App 解除安裝自動清理,安全無需權限。
package com.example.service;
import android.content.Context;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
public class LoginService {
private static final String FILE_NAME = "user.dat"; // 建議 .dat 或 .bin,避免誤以為可執行
/** 儲存帳號密碼 (明文示範,生產請加密!) */
public static boolean saveUserInfo(Context context, String username, String password) {
File file = new File(context.getFilesDir(), FILE_NAME);
try (FileOutputStream fos = new FileOutputStream(file)) {
String data = username + "##" + password; // 簡易分隔符
fos.write(data.getBytes("UTF-8"));
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/** 讀取帳號密碼 */
public static Map getUserInfo(Context context) {
File file = new File(context.getFilesDir(), FILE_NAME);
if (!file.exists()) return null;
try (FileInputStream fis = new FileInputStream(file);
BufferedReader br = new BufferedReader(new InputStreamReader(fis, "UTF-8"))) {
String line = br.readLine();
if (line == null) return null;
String[] parts = line.split("##", 2);
if (parts.length != 2) return null;
Map map = new HashMap<>();
map.put("username", parts[0]);
map.put("password", parts[1]);
return map;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
// 存檔
boolean ok = LoginService.saveUserInfo(this, "admin", "123456");
Log.d("TAG", "存檔 " + (ok ? "成功" : "失敗"));
// 讀檔
Map info = LoginService.getUserInfo(this);
if (info != null) {
String user = info.get("username");
String pwd = info.get("password");
// 自動填充登入框...
}
| 問題 | 解決方案 |
|---|---|
| 明文儲存密碼 | AES/GCM 加密 + Android Keystore 保護金鑰 |
| 分隔符衝突 | 改用 JSON (Gson/Moshi) 或 Protocol Buffers 序列化 |
| 大量/頻繁讀寫 | 改用 MMKV (微信開源、高效能 key-value) 或 Room |
| 多進程存取 | 檔案鎖 FileChannel.lock() 或跨進程 MMKV |