Original recipe: http://blog.greweb.fr/?p=1993
Generate Zip archive on-the-fly with Play Framework (2.1+)
package controllers | |
import java.io.{FileInputStream, InputStream} | |
import play.api.libs.iteratee._ | |
import play.api.mvc.{Action, _} | |
import scala.concurrent.ExecutionContext.Implicits.global | |
object Application extends Controller { | |
def zipRandom = Action { | |
val r = new java.util.Random() | |
val random: Enumerator[(String,InputStream)] = Enumerator(Range(0,100)).map(i => ("test-zip/README-"+i+".txt", new RandomStream(100000))) | |
Ok.chunked(ZipTool.multiZipStream(random) >>> Enumerator.eof).withHeaders( | |
"Content-Type"->"application/zip", | |
"Content-Disposition"->"attachment; filename=test.zip" | |
) | |
} | |
def zipFiles = Action { | |
val files: Enumerator[(String,InputStream)] = Enumerator(1,2,3).map(_.toString+".txt").map(f => (f, new FileInputStream(f))) | |
Ok.chunked(ZipTool.multiZipStream(files) >>> Enumerator.eof).withHeaders( | |
"Content-Type"->"application/zip", | |
"Content-Disposition"->"attachment; filename=test.zip" | |
) | |
} | |
def index = Action { | |
Ok(views.html.index("Your new application is ready.")) | |
} | |
} |
import play.api._ | |
import play.api.mvc._ | |
import play.api.libs.iteratee._ | |
import java.util.zip._ | |
import java.util.Random | |
class RandomStream(val count: Int) extends InputStream { | |
var index = 0 | |
val r = new Random() | |
val data = Range(0, count).map(_=>r.nextLong).map(_.toString).mkString("\n").map(_.toByte).toArray | |
def read(): Int = { | |
if(index < data.length){ | |
index += 1 | |
data(index-1) | |
} | |
else | |
-1 | |
} | |
} |
import java.io.ByteArrayOutputStream | |
import java.util.zip._ | |
import play.api.libs.iteratee._ | |
import scala.concurrent.ExecutionContext.Implicits.global | |
object ZipTool { | |
/** | |
* Writes Zip archive using Enumerator's | |
*/ | |
def multiZipStream(in: Enumerator[(String,java.io.InputStream)]) = { | |
val bs = new ByteArrayOutputStream | |
val zos = new ZipOutputStream(bs) | |
var r : Array[Byte] = null | |
def getReset(s: ByteArrayOutputStream) = { | |
r = s.toByteArray | |
s.reset() | |
r | |
} | |
val e = in.flatMap { case (fileName, is) => | |
// Entry header | |
Enumerator({ | |
//print("f") | |
zos.putNextEntry(new ZipEntry(fileName)) | |
getReset(bs) | |
}) >>> | |
// File parts | |
Enumerator.fromStream(is, 64 * 1024).map(data => { | |
//print(".") | |
zos.write(data) | |
getReset(bs) | |
}) >>> | |
// End of entry | |
Enumerator(1).map(_ => { | |
//print("c") | |
is.close() | |
zos.closeEntry() | |
getReset(bs) | |
}) | |
} >>> | |
// Close zip | |
Enumerator(1).map(_ => { | |
//print("|\n") | |
zos.close() | |
getReset(bs) | |
}) | |
// e.onDoneEnumerating({ println("Done streaming") }) | |
e | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment