使用Play 2.3有效地提供文件

时间:2014-06-19 13:49:24

标签: file scala playframework

我需要以文件形式提供来自Action的一些内容:基本上,我正在动态创建CSV内容并将其发送给客户端。

我无法使用sendFile,因为该文件确实不存在;我尝试使用chunked transfer,但是响应非常慢(在localhost中我得到的文件大约是100KB / s,我觉得这很奇怪)。

我有没有办法设置内容类型并逐行编写响应"而不必指定内容长度"先验"?

1 个答案:

答案 0 :(得分:2)

这是使用简单预定义Enumerator的一种方法,它将从写入OutputStream的字节产生响应:

def csv = Action {
    val enumerator = Enumerator.outputStream { out =>
       out.write(...)

       // Keep writing to the Enumerator

       out.close()
    }

    Ok.chunked(enumerator.andThen(Enumerator.eof)).withHeaders(
       "Content-Type" -> "text/csv", 
       "Content-Disposition" -> s"attachment; filename=test.csv"
    )
}

对于相对较小的文件(或者如果生成文件的过程本质上很慢),这很简单,但请注意,从文档中这没有背压,将大文件读入OutputStream如果客户端无法快速下载,可以快速填满内存。

<强>更新

经过多次测试后,您写入Byte的{​​{1}}数组的大小似乎会对吞吐量产生巨大影响。

使用此样本流:

OutputStream

以1KB的方式写入val s = Stream.continually(0.toByte) 这样的块会产生6MB / s的吞吐量:

OutputStream

但是,如果我一次只写10个字节,吞吐量会减慢到小于100KB / s。因此,我建议使用此方法以分块形式写入CSV,一次将多行写入(0 until 1024*1024).foreach{i => out.write(s.take(1024).toArray) } 而不是一次写入一行。