「初探Dart编程语言」-构建一个成绩查询系统之二
「初探Dart编程语言」-成绩查询系统之四
「初探Dart编程语言」-构建一个成绩查询系统之一
上一篇文章中我们创建了内存存储仓库,通过使用内存仓库我们可以实现对分数对象的基本管理功能,但内存存储仓库有一个严重的问题:程序重新启动,仓库中的数据全部丢失。为此,我们需要提供一种可以具备持久化能力的存储仓库。Dart语言提供了各种的IO功能,本文我们通过使用文件File对象再次实现Repo抽象类。由于IO操作是个耗时的行为,我们将使用异步方式实现所有Repo抽象类定义的方法,因此,新的Repo接口做下调整,如下图1所示。
文件读与写
读取文件数据
Dart提供了File对象用于进行文件操作。文件的读与写是最常用的操作,下图2中,第8行代码创建了一个File对象scoreFile,之后我们通过调用文件的openRead方法返回一个流对象,流对象之后经过两个转换器utf8.decoder和LineSplitter。utf8.decoder转换器将二进制数据转化为utf8编码的文本流,之后再经过LineSplitter转换器将其分割为以行为单位的文本流,如图2中第12行代码所示。
在处理每一行的数据之前,我们先看一下文件中存储的数据内容是什么格式的,如下图3所示。
图3为数据文件的内容,它以行为单位存储Score对象的内容,Score对象的成员信息使用竖线”|”进行分割,第一个数值表示Score的id字段值,第二个数值表示english字段值,第三个字段表示chinese字段,第四个数值表示science字段值,第五个数值表示math字段值,第六个数值表示physic字段值,最后一个数值表示studentNo字段值。
图2中代码第14行执行遍历数据行的内容,每次读取一行代码内容将其存放到line变量中,第15行代码则是对这一行的代码按照“|”分隔符将一行的内容进行分割为一个字符串列表,这个字符串列表解析完成之后会含有7个元素,分别对应Score对象中的7个成员值,但这些成员都是字符串类型,因此在构建Score对象的时候将这些字符串使用不同类型的解析器转换为对应类型的数值。第18-24行代码为各个字符串的解析方法,整型类型使用int.parse进行解析,浮点类型使用double.parse进行解析。完成类型转换之后就可以构建一个Score对象了,第25行代码将新构建的Score对象添加至scores列表中。最后将scores对象作为方法的返回值。
写文件数据
文件的写操作也使用了流的方式进行写入到文件。与读文件的操作相同,写文件也需要先创建一个文件对象,如图4中第34行代码所示,之后通过第35行代码调用方法openWrite返回一个流对象sink,之后我们将数据通过sink对象进行写入。第36-52行代码实现将列表对象中的元素一个一个地写入到sink流中,每一个列表元素构成一行数据,通过访问Score对象的成员将其写入至sink流中,各个成员之间使用分隔符“|”进行分割,图4中第38、40、42、44、46、48行代码都是写入分隔符,第50行代码使用writeln函数写入一个换行符,表示这一行内容的结束。当列表中的每一个元素都写入到sink流对象后,就可以调用flush方法,将这些数据写入到文件中了,如图4中第52行代码所示。
save方法
save方法是指将一个新的Score对象内容存储到当前的系统中。对于内存仓库来说,就是将Score对象添加至当前的列表对象中,对于文件仓库来说,它指的是将Score对象存储到文件中。图5中第105行代码调用了read方法,它将所有的Score对象从文件中读取出来,并保存至scores列表变量中,之后,第108行代码,将这个save方法的参数item对象添加至scores列表对象中,这样就实现了将item对象存储到了内存中,但是还没有保存至文件中,第109行代码则是将scores列表中的内容全部写入至文件,即新增的item对象也一并保存到了文件中。
remove方法
remove方法对于文件存储仓库来说是指将指定的元素从文件中删除。按照上一节的操作方式,我们首先还是将文件中的内容读取到一个列表对象中,如图6中第89行代码所示。之后使用列表对象的removeWhere方法将元素id值与参数id相同的元素删除,这样就从列表对象scores中删除了对应的元素,我们再通过第93行代码将删除后的列表内容全部写入至文件中,这样就实现了从文件中删除指定id的Score记录了。
update方法
update方法对于文件存储仓库来说是更新文件中的一条Score记录。对于文件来说,我们操作的是数据流,而不是一个一个的记录,如果需要更新文件的内容,我们需要重新写入文件的全部内容,就像之前的save和remove方法一样。第116行代码将原文件的内容全部读入至列表对象scores中,第117行代码使用firstWhere方法查找到第一个元素的id值与参数id值相同的Score对象,使用第119-124行代码进行更新这个Score对象,因为这样的更新操作都是在内存中完成的,同样需要将更新后的列表内容回写到文件中,正如代码第126行所示的那样。
findOne方法
findOne方法是从文件中查找一个元素id与参数id相同的元素。在进行查找元素时,我们是按照行为单位顺序进行读取,每读取一行Score记录,便会检测所读取的这样记录的id值是否与参数的id值相同,如果二者的值相同,表明当前读取的这条记录就是所要查询的结果,之后再使用这一行的内容进行构建Score对象,并将其返回。
findOne方法与上述的几个方法不同,他不是一次性读取所有的数据行,而是一次只读取一行,之后再判断是否需要继续进行读取操作,如果已经找到对应的对象,那么后续的内容就不需要再继续进行读取了,整个读取操作就终止了。
findOne方法与上述其它方法另一个所不同的地方是,它在分割完行数据之后,首先对id字段进行了解析,之后判断此id值是否与参数id值相同,如果二者的值不相同,那么后续的字段就无需再执行解析操作,只有二者的id值相同时,才会继续解析后续字段的内容,如图中第71-77行代码所示,完成字段的解析之后,就可以构建出对应的Score对象,并将其返回。
findAll方法
findAll方法是将文件中所有的Score对象构建出来,并以列表的方式返回。这个操作正是read方法实现的功能,因此,只需调用read方法,并将其返回值作为findAll方法的返回值即可,如下图9所示。
总结
Dart语言提供了强大的IO能力,既可以支持文件的读写操作,又可以支持网络的数据发送与接收操作,同时有提供了同步接口方法和异步接口方法。本文中使用文件演示了如何对文件中的一条或多条记录进行“增删改查”操作,重点是如何使用文件的流式写与读操作。
「初探Dart编程语言」-构建一个成绩查询系统之二
「初探Dart编程语言」-成绩查询系统之四
「初探Dart编程语言」-构建一个成绩查询系统之一