我已经阅读了一些关于通过Iteratee将文件发送到S3的可能性,这似乎允许在我们收到文件时发送一个文件的S3块,并避免出现大文件的OutOfMemory例如.
我发现这个SO帖子可能几乎是我需要做的事情: 播放2.x:使用Iteratees上传活动文件 我真的不明白该怎么做,或者如果它真的可以在Play 2.0.2中使用(因为Sadek Brodi说foldM仅在Play 2.1中提供,例如
有人可以通过简单的方式解释这一点,对于那些阅读过有关Iteratees的博客,还不是Scala/Play2专家的人来说?
我甚至不知道我是否应该使用多部分体分析器或类似的东西,但我知道的一件事是我不明白这段代码在做什么:
val consumeAMB =
Traversable.takeUpTo[Array[Byte]](1028*1028) &>> Iteratee.consume()
val rechunkAdapter:Enumeratee[Array[Byte],Array[Byte]] =
Enumeratee.grouped(consumeAMB)
val writeToStore: Iteratee[Array[Byte],_] =
Iteratee.foldM[Array[Byte],_](connectionHandle){ (c,bytes) =>
// write bytes and return next handle, probable in a Future
}
BodyParser( rh => (rechunkAdapter &>> writeToStore).map(Right(_)))
Run Code Online (Sandbox Code Playgroud)
顺便说一句,与使用经典Java InputStream/OutputStream相比,内存消耗会有什么不同.我实际上能够以非阻塞方式将500mb文件转发到S3,内存消耗非常低,不使用Iteratees,使用Java + AsyncHttpClient + Grizzly(但我想它也适用于Netty).
那么使用Iteratee有什么好处?
我可以看到的一个区别是我获取并转发到S3的InputStream在我的情况下由临时文件支持(这是一个CXF行为),因此它可能不像Play Iteratee那样具有反应性
但是对于Iteratees,如果Enumerator产生连接接收到的字节并通过Iteratee将它们转发给S3,那么如果与S3的连接不好并且字节无法快速转发,则存储"待定"字节?
我必须实现一个服务器,让一些用户可能将大量文件(数千兆字节的文件)上传到S3(虽然他们不知道它是S3).我已经在Python中实现了类似的东西,并使用Play框架实现了基本实现.
现在我的上传功能如下所示:
public Result uploadFile() {
List<Http.MultipartFormData.FilePart> files = request().body().asMultipartFormData().getFiles();
if (CollectionUtils.isNotEmpty(files)) {
Bucket bucket = MY_BUCKET;
UUID timeuuid;
Promise<UploadResult> promise;
ObjectNode responseMessage = Json.newObject();
for (Http.MultipartFormData.FilePart file : files) {
timeuuid = TimeUUID.now();
promise = Promise.promise(new UploadFunction(timeuuid, bucket, file.getFile(), obtainS3Connection()));
responseMessage.set(file.getFilename(), TextNode.valueOf(timeuuid.toString()));
}
return accepted(responseMessage);
} else {
return badRequest("files empty");
}
}
Run Code Online (Sandbox Code Playgroud)
我并不担心上传代码本身,实际上我已经实现了很多次.我担心的是让它变成Play!不将文件保存到磁盘,并且只发送文件"通过"我的服务器而不写入磁盘(即使是临时文件).我有一些处理涉及到某些内容的"客户端"加密,我可以做一个流.
我想知道Play是否已经这样做了?或者我将如何实现这一目标?
我假设Play(以及我之前版本的此服务中的Django)的作用是:
Upload --> Play MyProcessing -------> S3
\ /
\ /
Disk
Run Code Online (Sandbox Code Playgroud)
我想要它做什么:
Upload --> Play --> MyProcessing -------> S3
Run Code Online (Sandbox Code Playgroud)
我想这样做的原因是我希望有可能在具有非常小的磁盘的实例上部署我的服务,并且我还希望保证在上载后没有人能够找到未加密的文件(如果我选择加密它). …
我试图了解Play 2.0框架的反应I/O概念.为了从一开始就更好地理解,我决定跳过框架的助手来构造不同类型的迭代,并Iteratee从头开始编写一个自定义BodyParser来解析请求体.
从Iteratees和ScalaBodyParser文档中提供的信息开始,以及关于播放被动I/O的两个演示文稿,这就是我想出的:
import play.api.mvc._
import play.api.mvc.Results._
import play.api.libs.iteratee.{Iteratee, Input}
import play.api.libs.concurrent.Promise
import play.api.libs.iteratee.Input.{El, EOF, Empty}
01 object Upload extends Controller {
02 def send = Action(BodyParser(rh => new SomeIteratee)) { request =>
03 Ok("Done")
04 }
05 }
06
07 case class SomeIteratee(state: Symbol = 'Cont, input: Input[Array[Byte]] = Empty, received: Int = 0) extends Iteratee[Array[Byte], Either[Result, Int]] {
08 println(state + " " + input + " " + received) …Run Code Online (Sandbox Code Playgroud)