从MultipartFormData在Play2 /斯卡拉记忆拉文件(Pulling files f

2019-08-17 03:25发布

我目前使用使用Play2 /斯卡拉FileUploader的Javascript工具来上传文件到我的服务器如下:

def fileUploader = Action(parse.multipartFormData) { request =>
  request.body.file("qqfile").map { picture =>
    import java.io.File
    val filename = picture.filename 
    val contentType = picture.contentType
    picture.ref.moveTo(new File("/tmp",filename))
    Ok(Json.toJson(Map( "success" -> "true" )))
  }.getOrElse {
    Ok(Json.toJson(Map( "error" -> "error occured")))
  }
}

我只是在处理小文件(<10MB),我想用卡斯巴直接使用Mongo的驱动程序写入这些文件到蒙戈文档或GridFS的。 我知道我可以从磁盘中读取保存的文件,但有没有办法从内存中的所有处理这种不先缓冲磁盘上的文件?

这里的游戏文件建议编写自定义BodyParser( http://www.playframework.com/documentation/2.1.0/ScalaFileUpload ),但似乎并没有成为一个如何去写一个任何文件。 目前尚不清楚该API /执行从Scaladocs如何工作的。 我试图寻找MultiPartFormData源代码,看看它是如何工作的,但我似乎无法找到它在他们的Git回购:

https://github.com/playframework/Play20/tree/master/framework/src/play/src/main/scala/play/api/mvc

我搜索了不少,但似乎无法找到一个很好的例子。

Answer 1:

未测试Multipart的对象BodyParsers做了很多工作,为我们的。 我们需要做的第一件事写的处理程序FilePart 。 我这里假设你想要的文件部分的Array[Byte]

def handleFilePartAsByteArray: PartHandler[FilePart[Array[Byte]]] =
  handleFilePart {
    case FileInfo(partName, filename, contentType) =>
      // simply write the data to the a ByteArrayOutputStream
      Iteratee.fold[Array[Byte], ByteArrayOutputStream](
        new ByteArrayOutputStream()) { (os, data) =>
          os.write(data)
          os
        }.mapDone { os =>
          os.close()
          os.toByteArray
        }
  }

下一步是定义你的身体解析器:

def multipartFormDataAsBytes:BodyParser[MultipartFormData[Array[Byte]]] = 
  multipartFormData(handleFilePartAsByteArray)

然后,为了使用它,你指定它Action

def fileUploader = Action(multipartFormDataAsBytes) { request =>
  request.body.files foreach {
    case FilePart(key, filename, contentType, bytes) => // do something
  }
  Ok("done")
}

在上面的代码段的一些类型和方法是有点难找。 以下是你需要它的情况下,进口的完整列表:

import play.api.mvc.BodyParsers.parse.Multipart.PartHandler
import play.api.mvc.BodyParsers.parse.Multipart.handleFilePart
import play.api.mvc.BodyParsers.parse.Multipart.FileInfo
import play.api.mvc.BodyParsers.parse.multipartFormData
import play.api.mvc.MultipartFormData.FilePart
import play.api.libs.iteratee.Iteratee
import java.io.ByteArrayOutputStream
import play.api.mvc.BodyParser
import play.api.mvc.MultipartFormData


Answer 2:

播放API已经改变了体面的数额,因为这被张贴。 我有一个类似用途的情况下,我不想一个临时文件并翻译上面的成以下,这似乎在用的情况下播放2.6工作有人需要这样的:

def byteStringFilePartHandler: FilePartHandler[ByteString] = {
    case FileInfo(partName, filename, contentType) =>
      Accumulator(Sink.fold[ByteString, ByteString](ByteString()) { (accumulator, data) =>
        accumulator ++ data
      }.mapMaterializedValue(fbs => fbs.map(bs => {
        FilePart(partName, filename, contentType, bs)
      })))
}

def multipartFormDataAsBytes: BodyParser[MultipartFormData[ByteString]] =
  playBodyParsers.multipartFormData(byteStringFilePartHandler)

在控制器使用它,请确保你注入PlayBodyParsers和提供ExecutionContext ,进口等如下:

import akka.stream.scaladsl.Sink
import akka.util.ByteString
import javax.inject._
import play.api.libs.streams.Accumulator
import play.api.mvc.MultipartFormData.FilePart
import play.api.mvc._
import play.core.parsers.Multipart.{FileInfo, FilePartHandler}
import scala.concurrent.ExecutionContext


@Singleton
class HomeController @Inject()(cc: ControllerComponents, playBodyParsers: PlayBodyParsers)
                              (implicit ec: ExecutionContext) extends AbstractController(cc) {

  def index = Action(multipartFormDataAsBytes) { request =>
    request.body.file("image").foreach((image) => {
      val arr = image.ref.toByteBuffer.array()
      println(arr)
    })
    Ok("got bytes!")
  }
}


文章来源: Pulling files from MultipartFormData in memory in Play2 / Scala