Flutter 本地存储
文章目录
- Flutter 本地存储
- SharedPreferences
- 添加依赖
- 获取实例
- 写入
- 读取
- 删除
- 清空
- SQLite
- 添加依赖
- 定义数据库
- 定义数据模型
- DAO(数据访问对象)
- 使用
- 文件存储
- 添加依赖
- 常用目录
- 文件操作
- 目录操作
Flutter 本地存储
SharedPreferences
- 类型:键值对
- 适应场景:存放简单配置、用户偏好、Token
- 本质:SharedPreferences 本质是把键值对写到 Android 的
SharedPreferences和 iOS 的NSUserDefaults
添加依赖
dependencies:shared_preferences:^2.2.3获取实例
finalprefs=awaitSharedPreferences.getInstance();写入
prefs.setString('name','小明');prefs.setInt('age',18);prefs.setDouble('weight',70.5);prefs.setBool('sex',true);prefs.setStringList('address',['北京','上海','重庆']);读取
finalStringname=prefs.getString('name')??'';finalint age=prefs.getInt('age')??0;finaldouble weight=prefs.getDouble('weight')??0;finalbool sex=prefs.getBool('sex')??false;finalList<String>address=prefs.getStringList('address')??[];删除
awaitprefs.remove('name');清空
awaitprefs.clear();SQLite
- 类型:关系型数据库
- 适应场景:结构化业务数据、列表分页
添加依赖
dependencies:sqflite:^2.3.3path:^1.9.0path_provider:^2.1.4定义数据库
classDBManager{staticfinalDBManagerinstance=DBManager();Database?_db;Future<Database>getdbasync{_db??=awaitopen();return_db!;}Future<Database>open()async{finalStringdir=awaitgetDatabasesPath();finalStringdbPath=path.join(dir,'app.db');returnopenDatabase(dbPath,version:1,onCreate:_create);}void_create(Databasedb,int version)async{finalbatch=db.batch();finalStringsql=''' CREATE TABLE note( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, content TEXT, category TEXT DEFAULT 'DEFAULT', pinned INTEGER NOT NULL DEFAULT 0, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL ); ''';batch.execute(sql);batch.execute('CREATE INDEX idx_note_category ON note(category);');batch.execute('CREATE INDEX idx_note_updated_at ON note(updated_at DESC);');// execute将操作添加到队列中// commit执行有操作awaitbatch.commit(noResult:true);}voidclose()async{await_db?.close();_db=null;}}定义数据模型
classNote{finalint?id;finalStringtitle;finalString?content;finalStringcategory;finalint pinned;latefinalDateTimecreatedAt;latefinalDateTimeupdatedAt;Note({this.id,requiredthis.title,this.content,this.category='default',this.pinned=0,DateTime?createdAt,DateTime?updatedAt,}){this.createdAt=createdAt??DateTime.now();this.updatedAt=updatedAt??DateTime.now();}Map<String,Object?>toMap(){return{'id':id,'title':title,'content':content,'category':category,'pinned':pinned,'created_at':createdAt.millisecondsSinceEpoch,'updated_at':updatedAt.millisecondsSinceEpoch,};}factoryNote.fromMap(Map<String,Object?>map){returnNote(id:map['id']asint?,title:map['title']asString,content:map['content']asString?,category:map['category']asString,pinned:map['pinned']asint,createdAt:DateTime.fromMicrosecondsSinceEpoch(map['created_at']asint),updatedAt:DateTime.fromMicrosecondsSinceEpoch(map['updated_at']asint),);}@overrideStringtoString(){return'Note{id:$id, title:$title, content:$content, category:$category, pinned:$pinned, createdAt:$createdAt, updatedAt:$updatedAt}';}}DAO(数据访问对象)
classNoteDao{staticfinalNoteDaoinstance=NoteDao();Future<Database>get_db=>DBManager.instance.db;// 增Future<Note>insert(Notenode)async{finalid=await(await_db).insert('note',node.toMap()..remove('id'),conflictAlgorithm:ConflictAlgorithm.replace,);returnNote(id:id,title:node.title,content:node.content,category:node.category,pinned:node.pinned,createdAt:node.createdAt,updatedAt:node.updatedAt,);}// 删Future<int>delete(int id)async{return(await_db).delete('note',where:'id=?',whereArgs:[id]);}// 改Future<int>update(int id,Stringcontent)async{return(await_db).update('note',{'content':content,'updated_at':DateTime.now().millisecond},where:'id=?',whereArgs:[id],);}// 查Future<Note?>get(int id)async{finalrows=await(await_db).query('note',where:'id=?',whereArgs:[id],limit:1,);returnrows.isEmpty?null:Note.fromMap(rows.first);}// 查询多条Future<List<Note>>getList(int page,int pageSize,{String?category,String?keyword,})async{finalList<String>where=[];finalList<Object?>args=[];if(category!=null&&category.isNotEmpty){where.add('category=?');args.add(category);}if(keyword!=null&&keyword.isNotEmpty){where.add('(title LIKE ? OR content LIKE ?)');args.add('%${keyword}%');args.add('%${keyword}%');}finalrows=await(await_db).query('note',where:where.isEmpty?null:where.join(' AND '),whereArgs:args.isEmpty?null:args,orderBy:'pinned DESC, updated_at DESC',limit:pageSize,offset:page*pageSize,);varnoteList=rows.map(Note.fromMap).toList(growable:false);returnnoteList;}}使用
增:
vardao=NoteDao();dao.insert(Note(title:'日记1',content:'这是日记1的内容'));vardao=NoteDao();dao.insert(Note(title:'日记2',content:'这是日记2的内容',category:'日记2的分类',pinned:1,),);删:
vardao=NoteDao();dao.delete(1);改:
vardao=NoteDao();dao.update(3,'hello world');查:
vardao=NoteDao();varnote=awaitdao.get(3);print('note:${note}');ar dao=NoteDao();varlist=awaitdao.getList(0,30,keyword:'hello world');print('noteList:${list}');文件存储
path_provider是一个 Flutter 插件,本身不提供文件操作功能,负责获取跨平台的目录路径。
因为不同操作系统、不同设备的目录结构不同,手动硬编码路径会导致兼容性问题。path_provider提供了跨平台的统一 API。
添加依赖
dependencies:path_provider:^2.1.5常用目录
// 应用文档目录:存储用户数据,不会被系统自动清理finalDirectorydocDir=awaitgetApplicationDocumentsDirectory();// Android: /data/data/<包名>/app_flutter// iOS: /var/mobile/Containers/Data/Application/<UUID>/Documents// 应用支持目录:存储持久化数据finalDirectorysupportDir=awaitgetApplicationSupportDirectory();// Android: /data/data/<包名>/files(即 context.getFilesDir())// iOS: /var/mobile/Containers/Data/Application/<UUID>/Library/Application Support// 应用缓存目录:在空间不足是会自动清理finalDirectorycacheDir=awaitgetApplicationCacheDirectory();// Android: /data/data/<包名>/cache// iOS: /var/mobile/Containers/Data/Application/<UUID>/Library/Caches// 临时目录:每次应用重启可能被清理finalDirectorytmpDir=awaitgetTemporaryDirectory();// Android: /data/data/<包名>/cache// iOS: /var/mobile/Containers/Data/Application/<UUID>/tmp// 下载目录finalDirectory?downloadDir=awaitgetDownloadsDirectory();// Android: /storage/emulated/0/Download// macOS: ~/Downloads// 外部存储目录:Android专用需要申请权限finalDirectory?externalDir=awaitgetExternalStorageDirectory();// Android: /storage/emulated/0/Android/data/<包名>/files文件操作
- File:文件操作
- Directory:目录操作
- FileSystemEntity:文件系统实体基类
- Platform:获取操作系统信息
finaldir=awaitgetApplicationDocumentsDirectory();finalfile=File('${dir.path}/myfile.txt');// 写入文本awaitfile.writeAsString('hello');// 写入awaitfile.writeAsString('world',mode:FileMode.append);// 追加写入// 读取文本finalcontent=awaitfile.readAsString();// 流式写入finalsink=file.openWrite(mode:FileMode.append);sink.write('hello\n');sink.write('world\n');awaitsink.flush();awaitsink.close();// 文件信息finalstat=awaitfile.stat();// 获取文件元数据print('文件大小(字节):${stat.size}');print('文件修改时间:${stat.modified}');print('文件类型:${stat.type}');// 文件是否存在awaitfile.exists();// 文件移动/重命名finalnewDir=Directory('${dir.path}/abc');if(!awaitnewDir.exists()){awaitnewDir.create();}finalnewPath='${newDir.path}/efg.txt';file.rename(newPath);// 文件复制file.copy(newPath);// 文件删除awaitfile.delete();目录操作
// 创建目录finalparentDir=awaitgetApplicationDocumentsDirectory();finalDirectorydir=Directory('${parentDir.path}/mydir');awaitdir.create();// 递归创建目录awaitdir.create(recursive:true);// 递归创建目录awaitdir.delete(recursive:true);// 支持递归删除// 展示目录内容finaldir=awaitgetApplicationDocumentsDirectory();finalfiles=awaitdir.list().toList();for(finalentityinfiles){print('entity:${entity}');}// 深度遍历,展示目录内finalfiles=awaitdir.list(recursive:true).toList();for(finalentityinfiles){print('entity:${entity}');}