发布this帖后,使用自定义解析器/ Iteratee实现基于流的文件上传。当然,该帖子中的代码是旧的,不再编译。以下是我正在尝试的。
case class UploadIteratee(state: Symbol = 'Cont, input: Input[Array[Byte]] = Empty, received: Int = 0) extends Iteratee[Array[Byte], Either[Result, Int]] {
def fold[B](folder: Step[Array[Byte], Either[Result, Int]] => Future[B])(implicit ec: ExecutionContext): Future[B] = {
folder(
Step.Cont(in => in match {
case in: El[Array[Byte]] => copy(input = in, received = received + in.e.length)
case Empty => copy(input = in)
case EOF => copy(state = 'Done, input = in)
case _ => copy(state = 'Error, input = in)
}))
}
}
def send = Action(BodyParser(rh => new UploadIteratee).map(Right(_))) { request =>
Ok("Done")
}
这看起来是否正确且足以接受来自文件上传的流?我必须做一些愚蠢的事情才能得到以下编译错误。
type mismatch; found : controllers.MyController.UploadIteratee required:
play.api.libs.iteratee.Iteratee[Array[Byte],Either[play.api.mvc.SimpleResult,?]]
修改 我在Play 2.2.2。我很糟糕,我正在看2.3源代码。现在跟随编译
case class UploadIteratee(state: Symbol = 'Cont, input: Input[Array[Byte]] = Empty, received: Int = 0) extends Iteratee[Array[Byte], Either[SimpleResult, Int]] {
def fold[B](folder: Step[Array[Byte], Either[SimpleResult, Int]] => Future[B])(implicit ec: ExecutionContext): Future[B] = {
folder(
Step.Cont(in => in match {
case in: El[Array[Byte]] => copy(input = in, received = received + in.e.length)
case Empty => copy(input = in)
case EOF => copy(state = 'Done, input = in)
case _ => copy(state = 'Error, input = in)
}))
}
}
def send = Action(BodyParser(rh => new UploadIteratee).map(Right(_))) { request =>
Ok("Done")
}
wingedsubmariner:我正在尝试编写一个主体解析器,它接收文件上传功能的数据流。随后,我将不得不在流中收到的每条记录中填充另一个数据保存案例类。我对Iteratee
的理解仍然是原始的,所以任何指针都会受到赞赏。
答案 0 :(得分:-1)
无需为大多数任务编写自定义Iteratee
实现。而是使用Iteratee
的伴随对象中的工厂方法。在这种情况下,我们可以使用Iteratee.foreach
创建一个正文解析器,在收到每个数据块时执行某些操作:
val bodyParser = BodyParser { requestHeader =>
Iteratee.foreach[Array[Byte]] { block =>
// Do something with each block as it is received
}.map(Right(_))
}
更复杂的实现可能会使用Enumeratee
将传入的字节流分解为不同的记录,然后由Iteratee
使用。