HarmonyOS NEXT智能终端应用开发 课件 第7章 数据存储和访问_第1页
HarmonyOS NEXT智能终端应用开发 课件 第7章 数据存储和访问_第2页
HarmonyOS NEXT智能终端应用开发 课件 第7章 数据存储和访问_第3页
HarmonyOS NEXT智能终端应用开发 课件 第7章 数据存储和访问_第4页
HarmonyOS NEXT智能终端应用开发 课件 第7章 数据存储和访问_第5页
已阅读5页,还剩38页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第7章数据存储和访问程序在运行过程中会产生一些数据,有时,需要将这些产生的数据进行持久化存储,以便以后在需要的时候再次读取和使用。鸿蒙系统提供了基本的数据服务,包括使用便利的首选项方式存储数据、关系数据库方式存储数据,以及使用文件方式存储数据等机制。本章对鸿蒙常用的数据存储和访问方式进行介绍。目录7.1使用首选项Preferences存储数据7.2使用关系数据库存储数据7.3访问应用程序文件7.4案例:选择一个图像文件并显示7.5练习:一次选择多个文件并拷贝之7.1使用首选项Preferences存储数据用户首选项(Preferences)为应用提供基本的轻量级数据持久化能力,Preferences适用于保存用户的个性化设置,例如字体大小、是否开启夜间模式等基本的配置数据存储和访问能力。首选项Preferences默认使用XML格式进行存储,当然也支持其他类型的存储方式。7.1.1使用首选项存储和访问数据本节只介绍XML格式的数据存储。使用首选项Preferences进行数据存储和访问的一般过程如下:第一步:导入@kit.ArkData模块import{preferences}from'@kit.ArkData';第二步:获取Preferences实例letdataPreferences:preferences.Preferences|null=null;letoptions:preferences.Options={name:'myStore'};dataPreferences=preferences.getPreferencesSync(this.context,options);第三步:写入数据dataPreferences.putSync('startup',‘auto’);第四步:读取数据letval=dataPreferences.getSync('startup','default');第五步:删除数据,可选dataPreferences.deleteSync('startup');第六步:数据持久化(在修改数据后,这一步必须做)dataPreferences.flush((err:BusinessError)=>{if(err){console.error(`Failedtoflush.Code:${err.code},message:${err.message}`);return;}('Succeededinflushing.’);})第七步:订阅数据变更,可选letobserver=(key:string)=>{('Thekey'+key+'changed.’);}dataPreferences.on('change',observer);可以使用如下语句取消订阅:dataPreferences.off('change',observer);第八步:删除指定文件preferences.deletePreferences(this.context,options);下面举例说明如何使用首选项Preferences存储数据。这个例子使用Preferences存储一些数据,并且监听数据的变化,如果数据发生了变化,则将它们读取出来并显示在文本框中。为此,新建名为ch0701的鸿蒙工程,修改Index.ets为如下代码:import{preferences}from'@kit.ArkData';

@Entry@ComponentstructIndex{@Statedata:string='';

privatecontext=this.getUIContext().getHostContext()asContextprivateoptions:preferences.Options={name:'Store001'};privatedp:preferences.Preferences|null=null;

build(){Column(){Text(this.data).fontSize(20).fontWeight(FontWeight.Bold).height(200).width('100%').border({width:1,radius:3})Button('添加Preferences数据').height(40).width('100%').margin(10).onClick(()=>{this.dp=preferences.getPreferencesSync(this.context,this.options);this.dp.putSync('age',20);this.dp.putSync('name','张三');this.dp.on('change',(key:string)=>{this.data=this.data+'The'+key+'changed.';this.data=this.data+key+':'+this.dp?.getSync(key,'')+'\n';})this.dp.flushSync();//必须使用flush持久化数据})Button('修改Preferences数据').height(40).width('100%').margin(10).onClick(()=>{this.dp=preferences.getPreferencesSync(this.context,this.options);letage=this.dp.getSync('age',0);age=(age==20?30:20);this.dp.putSync('age',age);letname=this.dp.getSync('name','');name=(name=='张三'?'里斯':'张三');this.dp.putSync('name',name);this.dp.flushSync();//必须使用flush持久化数据})}.height('100%').width('100%')}}7.1.2首选项文件及其位置本质上,首选项数据保存于应用程序各自APP目录下的一个文件。例如,这个例子创建了一个名称为Store001的首选项,因此,鸿蒙系统在这个应用APP的目录下创建了名称为Store001的文件,如图。可以通过如图7-4所示的“SaveAs…”导出Store001文件,然后打开观察这个文件内容。7.2使用关系数据库存储数据当需要存储的数据量比较大时,可以使用关系数据库存储数据。鸿蒙支持基于SQLite的关系数据库存储。鸿蒙的关系型数据库接口对应用程序提供通用的数据库操作,其底层基于SQLite作为持久化存储引擎,支持SQLite具有的数据库特性,包括但不限于事务、索引、视图、触发器、外键、参数化查询和预编译SQL语句。7.2.1使用SQLite数据库存储数据使用SQLite关系型数据库接口操作数据库数据,需要首先使用如下语句导入relationalStore模块:import{relationalStore}from'@kit.ArkData';//导入模块然后创建一个relationalStore.StoreConfig对象用于指定数据库的相关配置,进而,再使用relationalStore.getRdbStore()获得relationalStore.RdbStore,之后便可以使用RdbStore的query()方法、insert()方法、update()方法、delete()方法等操作数据库中的数据。下面举一个例子说明如何使用关系型数据库存储应用程序数据。在这个例子的主界面上有Text组件,用于显示数据库中的数据,还有四个按钮:第一个按钮用于存储一些数据到数据库表中,第二个按钮则从数据库读取数据,并将数据显示在Text中,第三个按钮用于修改数据库中的数据,第四个按钮用于删除数据库中的数据。为此,新建一个名称为ch0702的鸿蒙工程,修改Index.ets为如下代码:import{relationalStore}from'@kit.ArkData';import{BusinessError}from'@kit.BasicServicesKit';

@Entry@ComponentstructIndex{@Statedata:string='';

//数据库配置对象privateSTORE_CONFIG:relationalStore.StoreConfig={name:'RdbTest.db',//数据库文件名securityLevel:relationalStore.SecurityLevel.S2,//数据库安全级别}//创建EMPLOYEE表的SQL语句privateSQL_CREATE_TABLE:string='CREATETABLEIFNOTEXISTS'+'EMPLOYEE(IDINTEGERPRIMARYKEYAUTOINCREMENT,NAMETEXTNOTNULL,'+'AGEINTEGER,SALARYREAL,CODESBLOB,IDENTITYUNLIMITEDINT)';privatecontext=this.getUIContext().getHostContext()asContextprivatestore:relationalStore.RdbStore|undefined=undefined;

onPageShow():void{relationalStore.getRdbStore(this.context,this.STORE_CONFIG,(err,store)=>{if(err){console.error(`FailedtogetRdbStore.Code:${err.code},message:${err.message}`);return;}this.store=store;

//当数据库创建时,数据库默认版本为0if(store.version===0){store.executeSql(this.SQL_CREATE_TABLE)//创建数据表.then(()=>{store.version=1;//为1,表示已经建表}).catch((err:BusinessError)=>{console.error(`FailedtoexecuteSql.Code:${err.code},message:${err.message}`);});}})}

onPageHide():void{this.store?.close();}

addData(){letvalue1='Lisa';letvalue2=18;letvalue3=100.5;letvalue4=newUint8Array([1,2,3,4,5]);letvalue5=BigInt('15822401018187971961171');constvalueBucket1:relationalStore.ValuesBucket={'NAME':value1,'AGE':value2,'SALARY':value3,'CODES':value4,'IDENTITY':value5,};

if(this.store!==undefined){this.store.insert('EMPLOYEE',valueBucket1,(err:BusinessError,rowId:number)=>{if(err){console.error(`Failedtoinsertdata.Code:${err.code},message:${err.message}`);return;}(`Succeededininsertingdata.rowId:${rowId}`);})}}

queryData(){letpredicates2=newrelationalStore.RdbPredicates('EMPLOYEE');//predicates2.equalTo('NAME','Rose');if(this.store!==undefined){this.store.query(predicates2,['ID','NAME','AGE','SALARY','IDENTITY'],(err:BusinessError,resultSet)=>{if(err){console.error(`Failedtoquerydata.Code:${err.code},message:${err.message}`);return;}//resultSet结果集,默认指向第-1个记录,有效的数据从0开始。while(resultSet.goToNextRow()){constid=resultSet.getLong(resultSet.getColumnIndex('ID'));constname=resultSet.getString(resultSet.getColumnIndex('NAME'));constage=resultSet.getLong(resultSet.getColumnIndex('AGE'));constsalary=resultSet.getDouble(resultSet.getColumnIndex('SALARY'));constidentity=resultSet.getValue(resultSet.getColumnIndex('IDENTITY'));this.data=this.data+'\n'+'id:'+id+'.name:'+name+'.age:'+age+'.salary:'+salary;}//释放数据集的内存resultSet.close();})}}

deleteData(){//删除数据//创建表'EMPLOYEE'的predicates,也就是条件letpredicates1=newrelationalStore.RdbPredicates('EMPLOYEE');predicates1.equalTo('NAME','Lisa');//条件:删除名字为Lisa的记录if(this.store!==undefined){this.store.delete(predicates1,(err:BusinessError,rows:number)=>{if(err){console.error(`Failedtodeletedata.Code:${err.code},message:${err.message}`);return;}(`Deleterows:${rows}`);})}}updateData(){letvalue1='Rose';letvalue2=22;letvalue3=200.5;letvalue4=newUint8Array([1,2,3,4,5]);letvalue5=BigInt('15822401018187971967863');

constvalueBucket4:relationalStore.ValuesBucket={'NAME':value1,'AGE':value2,'SALARY':value3,'CODES':value4,'IDENTITY':value5,};

//修改数据//创建表'EMPLOYEE'的predicates,也就是条件letpredicates1=newrelationalStore.RdbPredicates('EMPLOYEE');predicates1.equalTo('NAME','Lisa');//匹配表'EMPLOYEE'中'NAME'为'Lisa'的字段if(this.store!==undefined){this.store.update(valueBucket4,predicates1,(err:BusinessError,rows:number)=>{if(err){console.error(`Failedtoupdatedata.Code:${err.code},message:${err.message}`);return;}(`Succeededinupdatingdata.rowcount:${rows}`);})}}build(){Column(){Text(this.data).fontSize(20).fontWeight(FontWeight.Bold).height(200).width('100%').border({width:1,radius:3})Button('新增数据').width('100%').height('30').margin(10).onClick(()=>{this.addData();this.data='';})Button('显示数据').width('100%').height('30').margin(10).onClick(()=>{this.queryData();})Button('删除数据').width('100%').height('30').margin(10).onClick(()=>{this.deleteData();this.data='';})Button('修改数据').width('100%').height('30').margin(10).onClick(()=>{this.updateData();this.data='';})}.height('100%').width('100%').justifyContent(FlexAlign.Start)}}7.2.2SQLite数据库文件及其位置与使用首选项方式存储数据类似,使用关系型数据库存储数据,在应用目录下也会用指定的数据库名字创建一个文件。例如,在这个程序例子中,使用如下语句创建了数据库配置选项:

privateSTORE_CONFIG:relationalStore.StoreConfig={name:'RdbTest.db',//数据库文件名

securityLevel:relationalStore.SecurityLevel.S2,//数据库安全级别

}当创建RdbStore实例时,会在应用程序目录下创建名称为RdbTest.db的数据库文件,如图。7.3访问应用程序文件如果首选项以及关系型数据库都不能满足应用程序存储数据的要求,可以使用原始文件直接存储数据,也就是说,应用程序可以对应用程序文件目录下的数据类文件进行创建、查看、读写、删除、移动、复制、获取属性等访问操作。7.3.1文件访问一般过程在应用程序可以对应用程序数据文件进行访问之前,首先需要获取应用程序数据文件的路径。可以通过上下文对象获取应用程序数据文件的路径。例如,在页面文件中,可以使用如下语句获得应用程序数据文件的路径:letcontext=this.getUIContext().getHostContext()ascommon.UIAbilityContext;letfilesDir=context.filesDir;其中的filesDir就是页面所在模块的数据文件路径。一旦获得了数据文件路径,就可以使用fileIo模块对文件进行读写。但是,需要首先通过如下语句导入fileIo模块:import{fileIoasfs,ReadOptions}from'@kit.CoreFileKit';之后,可以使用fileIo模块的openSync()方法打开文件,使用writeSync()方法向文件写入数据,使用readSync()方法从文件中读取数据,使用closeSync()方法关闭文件,以及使用listFileSync()方法列表目录下的文件。下面举一个例子说明如何访问应用程序的数据文件。这个程序在功能首界面显示一组功能按钮,点击不同按钮完成各种不同的文件操作功能。为此,首先创建名为ch0703的鸿蒙工程,修改Index.ets为如下内容:import{common}from'@kit.AbilityKit';import{fileIoasfs,ReadOptions}from'@kit.CoreFileKit';import{buffer}from'@kit.ArkTS';

@Entry@ComponentstructIndex{@Statetext:string='';privatecontext=this.getUIContext().getHostContext()ascommon.UIAbilityContext;

writeData(){letfilesDir=this.context.filesDir;//文件不存在时创建并打开文件,文件存在时打开文件letfile=fs.openSync(filesDir+'/test.txt',fs.OpenMode.READ_WRITE|fs.OpenMode.CREATE);//将界面上输入文本的数据写入到文件letwriteLen=fs.writeSync(file.fd,this.text);fs.closeSync(file);}

readData(){letfilesDir=this.context.filesDir;letfile=fs.openSync(filesDir+'/test.txt',fs.OpenMode.READ_ONLY);if(!file){("文件不存在,打开文件失败!");return;}

letarrayBuffer=newArrayBuffer(1024);//设置读取的偏移量和长度letreadOptions:ReadOptions={offset:0,length:arrayBuffer.byteLength};letreadLen=fs.readSync(file.fd,arrayBuffer,readOptions);//将ArrayBuffer对象转换为Buffer对象,并转换为字符串输出letbuf=buffer.from(arrayBuffer,0,readLen);this.text='从文件中读取的数据:'+buf.toString();//关闭文件fs.closeSync(file);}

deleteFile(){letfilesDir=this.context.filesDir;fs.unlink(filesDir+'/test.txt');}

listDir(){letfilesDir=this.context.filesDir;letfns:string[]=fs.listFileSync(filesDir);fns.forEach((n:String)=>{this.text='';this.text=this.text+'\n'+n+'\n';});}

build(){Column(){TextArea({text:$$this.text,placeholder:'inputyourword...'}).width('95%').height(200).margin(5).border({width:2,radius:8}).fontSize(24)

Grid(){GridItem(){Button('写入数据').width('100%').height('100%').fontSize(20).backgroundColor(Color.Gray).onClick(()=>{this.writeData();})}GridItem(){Button('读取数据').width('100%').height('100%').fontSize(20).backgroundColor(Color.Gray).onClick(()=>{this.readData();})}GridItem(){Button('删除文件').width('100%').height('100%').fontSize(20).backgroundColor(Color.Gray).onClick(()=>{this.deleteFile();})}GridItem(){Button('列表目录').width('100%').height('100%').fontSize(20).backgroundColor(Color.Gray).onClick(()=>{this.listDir();})}}.width('100%').height(140).margin(20).rowsTemplate('1fr1fr').columnsTemplate('1fr1fr').columnsGap(10).rowsGap(15)}.width('100%').height('100%').justifyContent(FlexAlign.Start)}}7.3.2应用程序数据文件存放位置应用程序的文件存放位置,根据创建文件时使用的上下文对象不同而存放于不同的位置。由于这个例子程序是基于entry模块的上下文创建的,因此,所创建的文件存放在entry的files目录下,如图。7.4案例:选择一个图像文件并显示作为数据存储和文件操作的总结,同时,也为了介绍如何使用鸿蒙系统提供的各种类型的文件Picker选择用户文件,本案例允许用户通过Picker选择一个图像文件,然后使用文件操作将用户选择的文件显示在界面上。7.4.1案例目标设计一个程序,该程序首先在主界面上显示表示空缺图像的占位图,点击该占位图,将打开一个对话框,在对话框中列表文件目录,用户可以在对话框中选择一个图像文件,确定后将用户选择的图像显示在占位图像框中。7.4.2案例分析鸿蒙平台强化了对文件系统的安全性管理。鸿蒙平台将文件系统文件划分为三个类别:系统文件、应用文件、用户文件,其中,系统文件是操作系统的一部分,对开发者和用户来来说,这部分文件都是在隐含使用的;应用文件是归属于应用程序的文件,包括应用程序代码文件、资源文件、配置文件、数据文件等,这部分文件对开发者也是部分可见的,例如,在7.3节介绍的内容就是用于操作应用程序数据文件的;用户文件则是归属于用户的,也就是使用鸿蒙手机/电脑/平板等的用户,这部分文件仅仅是用户可见的,并且,不同用户的用户文件也是相互隔离的。为了保证对用户文件访问的安全性以及便利对用户文件的访问,鸿蒙系统提供了一组称为Picker的功能组件专门用户在获得用户授权的情况下访问用户文件,包括用户文档文件、用户图片文件、用户音频文件:使用PhotoAccessHelper访问图片视频文件;使用DocumentViewPicker访问用户文档文件;使用AudioViewPicker访问用户音频文件。这个案例介绍了如何使用PhotoAccessHelper访问图片文件。首先使用如下语句导入需要的模块:import{photoAccessHelper}from'@kit.MediaLibraryKit'然后构建PhotoSelectOptions对象以指定要选择的文件类型等相关参数,最后构建PhotoViewPicker对象并调用其select()方法选择文件。完整的代码在案例实施一节给出。7.4.3案例实施新建名称为ch0704的鸿蒙工程,在ets目录下新建images文件,并在其中放置用于表示图像占位图的图片,然后修改Index.et

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论