如何在play框架中上传一个巨大的文件?

b s*_*ngh 4 playframework-2.0

在我的应用程序中,我试图将文件上传到目标文件夹,浏览器不允许我上传大小超过4 GB的文件,我的文件大小为15 GB.我很震惊,不知道如何上传它.任何帮助都非常值得赞赏.

aru*_*nov 18

你可以在两个阶段解决这个问题:

  1. 您需要将大文件拆分为较小的块,然后将它们发送到服务器.为此,您可以使用某些javascriptResumable.js
  2. 在您的play2控制器中,您需要使用IterateeAPI 组装这些块,然后您可以使用您的文件执行任何操作.

编辑:

让我们resumable.js以客户端为例,我不会深入了解细节,您可以在这里找到文档和示例

我们的视图将是极简主义的(仅选择一个或多个文件的链接):

@()
@main("File upload"){
    <a href="#" id="browseButton">Select files</a>
}
Run Code Online (Sandbox Code Playgroud)

我们的javasctipt:

$(function(){
  var r = new Resumable({
    target:'/test/upload'
  });

  r.assignBrowse(document.getElementById('browseButton'));

  r.on('fileSuccess', function(file){
    console.debug(file);
  });
  r.on('fileProgress', function(file){
    console.debug(file);
  });
  // more events, look API docs
});
Run Code Online (Sandbox Code Playgroud)

我们的main.scala.html:

@(title: String)(content: Html)

<!DOCTYPE html>

<html>
    <head>
        <title>@title</title>
        <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
        <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/style.css")">
        <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
        <script src="@routes.Assets.at("javascripts/jquery-1.9.0.min.js")" type="text/javascript"></script>
        @*We include resumable.js library*@
        <script src="@routes.Assets.at("javascripts/resumable.js")" type="text/javascript"></script>
        @*Our javascript for file upload*@
        <script src="@routes.Assets.at("javascripts/upload.js")" type="text/javascript"></script>
    </head>
    <body>
        @content
    </body>
</html>
Run Code Online (Sandbox Code Playgroud)

我们的服务器端,在播放控制器中:

首先,我们需要创建一个函数,通过使用我们的通道并生成结果来处理我们的文件部分 - 在我们的示例中为Array [Byte].

 // hadle file part as 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
        }
Run Code Online (Sandbox Code Playgroud)

然后我们可以定义一个自定义的身体解析器:

// custom body parser to handle file part as Array[Byte]
  def multipartFormDataAsBytes:BodyParser[MultipartFormData[Array[Byte]]] =
    multipartFormData(handleFilePartAsByteArray)
Run Code Online (Sandbox Code Playgroud)

最后我们的控制器可能看起来像:

def handleFileUpload = Action(multipartFormDataAsBytes){ request =>
 // retrieve file name from data part   
 val fileName  = request.body.asFormUrlEncoded.get("resumableFilename").get.headOption
 // retrieve arrays of byte from file part and write them to file
    request.body.files foreach{
      case FilePart(key,filename,content,bytes)=>
        import scalax.io._
        val output:Output = Resource.fromFile(fileName.getOrElse("default"))
        output.write(bytes)
    }
    Ok("")
  }
Run Code Online (Sandbox Code Playgroud)

控制器的导入列表:

import play.api.mvc._
import play.api.mvc.BodyParsers.parse.Multipart._
import play.api.libs.iteratee.Iteratee
import java.io.ByteArrayOutputStream
import play.api.mvc.BodyParsers.parse._
import play.api.mvc.BodyParsers.parse.Multipart.FileInfo
import play.api.mvc.MultipartFormData.FilePart
Run Code Online (Sandbox Code Playgroud)