设为首页 加入收藏

TOP

FunDA(5)- Reactive Streams:Play with Iteratees(四)
2017-10-09 14:30:11 】 浏览:826
Tags:FunDA Reactive Streams Play with Iteratees
mmy--Kate--Chris res0: scala.concurrent.Future[Unit] = Success(())

Enumerator usersEnum把输入推送给userIteratee、userIteratee在完成时直接把它们印了出来。在play-iterate库Iteratee对象里有个fold函数(Iteratee.fold)。这是个通用的函数,可以轻松实现上面这个userIteratee和其它的汇总功能Iteratee。Iteratee.fold函数款式如下: 

def fold[E, A](state: A)(f: (A, E) => A): Iteratee[E, A]

我们可以用这个fold函数来构建一个相似的Iteratee:

val userIteratee2 = Iteratee.fold(List[String]())((st, el:String) => st :+ el) //> userIteratee2 : play.api.libs.iteratee.Iteratee[String,List[String]] = Cont(<function1>)
(usersEnum |>>> userIteratee2).foreach {x => println(x)} //| List(Tiger, John, Jimmy, Kate, Chris)

下面是另外两个用fold函数的例子:

val inputLength: Iteratee[String,Int] = { Iteratee.fold[String,Int](0) { (length, chars) => length + chars.length } //> inputLength : play.api.libs.iteratee.Iteratee[String,Int] = Cont(<function1>)
} Await.result((usersEnum |>>> inputLength),Duration.Inf) //> res1: Int = 23
val consume: Iteratee[String,String] = { Iteratee.fold[String,String]("") { (result, chunk) => result ++ chunk } //> consume : play.api.libs.iteratee.Iteratee[String,String] = Cont(<function1 >)
} Await.result((usersEnum |>>> consume),Duration.Inf) //> res2: String = TigerJohnJimmyKateChris

从以上的练习里我们基本摸清了定义Iteratee的两种主要模式:

1、构建新的Iteratee,重新定义fold函数,如上面的userIteratee及下面这个上传大型json文件的例子:

object ReactiveFileUpload extends Controller { def upload = Action(BodyParser(rh => new CsvIteratee(isFirst = true))) { request => Ok("File Processed") } } case class CsvIteratee(state: Symbol = 'Cont, input: Input[Array[Byte]] = Empty, lastChunk: String = "", isFirst: Boolean = false) extends Iteratee[Array[Byte], Either[Result, String]] {
 def fold[B]( done: (Either[Result, String], Input[Array[Byte]]) => Promise[B], cont: (Input[Array[Byte]] => Iteratee[Array[Byte], Either[Result, String]]) => Promise[B], error: (String, Input[Array[Byte]]) => Promise[B] ): Promise[B] = state match { case 'Done =>
 done(Right(lastChunk), Input.Empty) case 'Cont => cont(in => in match {
      case in: El[Array[Byte]] => { // Retrieve the part that has not been processed in the previous chunk and copy it in front of the current chunk
        val content = lastChunk + new String(in.e) val csvBody =
          if (isFirst) // Skip http header if it is the first chunk
            content.drop(content.indexOf("\r\n\r\n") + 4) else content val csv = new CSVReader(new StringReader(csvBody), ';') val lines = csv.readAll // Process all lines excepted the last one since it is cut by the chunk
        for (line <- lines.init) processLine(line) // Put forward the part that has not been processed
        val last = lines.last.toList.mkString(";") copy(input = in, lastChunk = last, isFirst = false) } case Empty => copy(input = in, isFirst = false) case EOF => copy(state = 'Done, input = in, isFirst = false)
      case _ => copy(state = 'Error, input = in, isFirst = false)
 }) case _ => error("Unexpected state", input) } def processLine(line: Array[String]) = WS.url("http://localhost:9200/affa/na/").post( toJson( Map( "date" -> toJson(line(0)), "trig" -> toJson(line(1)), "code" -> toJson(line(2)), "nbjours" -> toJson(line(3).toDouble) ) ) ) }

二、直接定义Cont

首页 上一页 1 2 3 4 5 下一页 尾页 4/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇FunDA(3)- 流动数据行操作:FD.. 下一篇FunDA(6)- Reactive Streams:..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目