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}');}