前言
大家好,我是鲫小鱼。是一名不写前端代码
的前端工程师,热衷于分享非前端的知识,带领切图仔逃离切图圈子,欢迎关注我,微信公众号:《鲫小鱼不正经》
。欢迎点赞、收藏、关注,一键三连!!
第十三章:数据存储与本地持久化
一、理论讲解:本地存储方式与原理
1.1 为什么需要本地存储?
- 持久化用户数据、脚本配置、历史记录、缓存内容
- 离线场景下数据可用,提升用户体验
- 支持数据同步、备份、迁移、恢复
1.2 常见本地存储方式
- 文件存储(files 模块):文本、JSON、二进制、图片、日志等
- 键值存储(storage 模块):轻量级配置、状态、缓存
- 数据库存储(sqlite):结构化数据、批量数据、复杂查询
- 缓存机制:内存缓存、磁盘缓存、定期清理
- 加密存储:敏感信息加密、Token、账号密码
1.3 存储原理与适用场景
- 文件系统:适合大文件、日志、图片、批量数据
- 键值对:适合配置、状态、少量数据
- 数据库:适合结构化、复杂、多表数据
- 缓存:适合高频、临时、可丢弃数据
二、代码示例:Auto.js 本地存储全场景实战
2.1 文件读写(文本/JSON/二进制/图片)
javascript
// 写入文本文件
files.write("/sdcard/demo.txt", "Hello, Auto.js!");
// 读取文本文件
var txt = files.read("/sdcard/demo.txt");
log("读取内容:" + txt);
// 写入 JSON 文件
var data = { user: "fish", time: Date.now() };
files.write("/sdcard/data.json", JSON.stringify(data, null, 2));
// 读取 JSON 文件
var obj = JSON.parse(files.read("/sdcard/data.json"));
log("用户:" + obj.user);
// 写入二进制文件(如图片)
if(requestScreenCapture()){
var img = captureScreen();
images.save(img, "/sdcard/screenshot.png");
toast("截图已保存");
}
// 读取图片
var img2 = images.read("/sdcard/screenshot.png");
if(img2) toast("图片读取成功");
2.2 文件追加、批量写入与分批处理
javascript
// 追加日志
files.append("/sdcard/log.txt", new Date().toLocaleString() + " 脚本启动\n");
// 批量写入数据
var arr = [];
for(let i=0;i<100;i++) arr.push({id:i, time:Date.now()});
files.write("/sdcard/batch.json", JSON.stringify(arr));
// 分批写入大数据
function writeInBatches(data, batchSize, filePath){
for(let i=0;i<data.length;i+=batchSize){
let batch = data.slice(i, i+batchSize);
files.append(filePath, JSON.stringify(batch) + "\n");
}
}
writeInBatches(arr, 20, "/sdcard/batch.log");
2.3 文件遍历、删除与清理
javascript
// 遍历目录下所有文件
files.listDir("/sdcard/", function(name){
log("文件:" + name);
});
// 删除文件
if(files.exists("/sdcard/demo.txt")) files.remove("/sdcard/demo.txt");
// 清理目录
function clearDir(dir){
files.listDir(dir, function(name){
files.remove(files.join(dir, name));
});
}
clearDir("/sdcard/temp");
2.4 键值存储(storage 模块)
javascript
// 创建/获取 storage
var store = storages.create("my_config");
// 写入键值
store.put("token", "abc123");
// 读取键值
var token = store.get("token", "");
log("Token:" + token);
// 删除键值
store.remove("token");
// 清空所有数据
store.clear();
2.5 数据库存储(sqlite)
javascript
// 打开数据库
var db = SQLiteDatabase.openOrCreateDatabase("/sdcard/demo.db", null);
// 创建表
db.execSQL("CREATE TABLE IF NOT EXISTS user (id INTEGER PRIMARY KEY, name TEXT, time INTEGER)");
// 插入数据
for(let i=0;i<10;i++){
db.execSQL("INSERT INTO user (name, time) VALUES (?, ?)", ["fish"+i, Date.now()]);
}
// 查询数据
var cursor = db.rawQuery("SELECT * FROM user", null);
while(cursor.moveToNext()){
log("用户:" + cursor.getString(1) + ", 时间:" + cursor.getLong(2));
}
cursor.close();
db.close();
2.6 配置文件读写与自动备份
javascript
// 读写配置文件
var config = { interval: 10, autoStart: true };
files.write("/sdcard/config.json", JSON.stringify(config));
var conf = JSON.parse(files.read("/sdcard/config.json"));
log("配置:" + JSON.stringify(conf));
// 自动备份
function backupFile(src, dest){
if(files.exists(src)) files.copy(src, dest);
}
backupFile("/sdcard/data.json", "/sdcard/backup/data_bak.json");
2.7 加密存储与敏感信息保护
javascript
// 简单加密存储(Base64)
function encodeBase64(str){
return java.util.Base64.getEncoder().encodeToString(java.lang.String(str).getBytes());
}
function decodeBase64(str){
return java.lang.String(java.util.Base64.getDecoder().decode(str));
}
var secret = encodeBase64("my_password");
files.write("/sdcard/secret.txt", secret);
var pwd = decodeBase64(files.read("/sdcard/secret.txt"));
log("解密后密码:" + pwd);
2.8 缓存机制与数据同步
javascript
// 简单内存缓存
var cache = {};
function setCache(key, value){ cache[key] = value; }
function getCache(key){ return cache[key]; }
// 磁盘缓存(如图片)
function cacheImage(url, path){
if(!files.exists(path)){
var res = http.get(url);
if(res.statusCode==200) files.writeBytes(path, res.body.bytes());
}
return images.read(path);
}
// 数据同步
function syncLocalToRemote(localPath, remoteUrl){
var data = files.read(localPath);
http.post(remoteUrl, { data });
}
2.9 数据清理与定期维护
javascript
// 定期清理日志
function cleanOldLogs(dir, days){
var now = Date.now();
files.listDir(dir, function(name){
var path = files.join(dir, name);
if(files.isFile(path)){
var last = files.lastModified(path);
if(now - last > days*24*3600*1000) files.remove(path);
}
});
}
cleanOldLogs("/sdcard/logs", 7);
2.10 移动端适配与多设备兼容
javascript
// 获取存储路径
var sdPath = files.getSdcardPath();
log("SD卡路径:" + sdPath);
// 判断文件/目录是否存在
if(files.exists(sdPath+"/autojs")) log("目录存在");
// 兼容不同 Android 版本
if(device.sdkInt >= 30){
log("Android 11+,需适配分区存储");
}
三、实战项目:自动记录签到历史与本地缓存工具
3.1 项目需求
- 自动记录每次签到结果到本地 JSON 文件
- 支持历史查询、导出、清理、备份
- 支持缓存常用数据,提升性能
- 支持数据同步与恢复
3.2 项目结构
plaintext
autojs-datastore/
├── main.js
├── modules/
│ ├── datastore.js
│ └── logger.js
├── data/
│ └── history.json
├── backup/
│ └── history_bak.json
├── logs/
│ └── data.log
└── README.md
3.3 datastore.js 数据存储模块
javascript
// modules/datastore.js
function saveHistory(record){
var path = "../data/history.json";
var arr = files.exists(path) ? JSON.parse(files.read(path)) : [];
arr.push(record);
files.write(path, JSON.stringify(arr, null, 2));
}
function getHistory(){
var path = "../data/history.json";
if(files.exists(path)) return JSON.parse(files.read(path));
return [];
}
function clearHistory(){
files.write("../data/history.json", "[]");
}
function backupHistory(){
files.copy("../data/history.json", "../backup/history_bak.json");
}
module.exports = { saveHistory, getHistory, clearHistory, backupHistory };
3.4 main.js 主流程
javascript
// main.js
const ds = require("./modules/datastore.js");
const logger = require("./modules/logger.js");
// 新增签到记录
var record = { user: "fish", time: Date.now(), status: "success" };
ds.saveHistory(record);
logger.log("签到记录已保存");
// 查询历史
var history = ds.getHistory();
history.forEach(r => logger.log(JSON.stringify(r)));
// 备份历史
ds.backupHistory();
logger.log("历史已备份");
// 清理历史
// ds.clearHistory();
// logger.log("历史已清空");
3.5 logger.js 日志模块
javascript
// modules/logger.js
function log(msg) {
let line = `[${new Date().toLocaleTimeString()}] ${msg}`;
files.append("../logs/data.log", line + "\n");
toast(msg);
}
module.exports = { log };
3.6 history.json 示例
json
[
{ "user": "fish", "time": 1710000000000, "status": "success" },
{ "user": "cat", "time": 1710000001000, "status": "fail" }
]
四、常见问题与解决方案
问题 | 解决方案 |
---|---|
文件读写失败/权限不足 | 检查存储权限、路径、Android 版本适配 |
JSON 解析报错/数据丢失 | 检查数据格式、加 try-catch、备份恢复 |
数据库操作异常/表不存在 | 检查 SQL 语句、表结构、路径 |
键值存储丢失/覆盖 | 检查 key 命名、加锁、分批写入 |
批量写入卡顿/内存溢出 | 分批处理、异步写入、优化数据结构 |
缓存失效/数据不同步 | 优化缓存逻辑、定期同步、加日志 |
加密存储解密失败 | 检查加密算法、密钥、数据格式 |
备份失败/恢复异常 | 检查文件路径、权限、备份逻辑 |
数据清理误删/恢复困难 | 增加确认、备份、日志记录 |
多设备兼容性问题 | 适配不同 Android 版本、存储路径、分区存储 |
数据同步冲突/覆盖 | 加锁、队列、分片处理,避免并发写入 |
目录遍历慢/卡顿 | 优化遍历逻辑、异步处理、分页加载 |
图片/二进制文件损坏 | 检查写入逻辑、加校验、异常处理 |
五、性能优化建议
- 批量/分批写入,避免一次性大数据操作
- 合理缓存数据,减少磁盘读写
- 日志分级输出,便于排查问题
- 异步处理耗时操作,主线程只做调度
- 定期清理无用数据,释放存储空间
- 数据加密压缩,提升安全与效率
- 备份与恢复机制,防止数据丢失
- 适配不同 Android 版本与分区存储
- 合理 sleep,避免无效等待
- 及时释放资源,防止内存泄漏
- 关键节点加详细日志,便于追踪
- 目录遍历/数据加载分页处理,提升流畅度
- 适配移动端存储波动,自动切换路径
最后感谢阅读!欢迎关注我,微信公众号:
《鲫小鱼不正经》
。欢迎点赞、收藏、关注,一键三连!!!