Skip to content

Instantly share code, notes, and snippets.

@hermanbanken
Forked from gre/Application.scala
Last active March 19, 2021 18:25
Show Gist options
  • Save hermanbanken/3af6bfea6e2ec462be52 to your computer and use it in GitHub Desktop.
Save hermanbanken/3af6bfea6e2ec462be52 to your computer and use it in GitHub Desktop.
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