2
votes

I want to process a large local file with Play. The file should be deleted from the filesystem right after it's been processed. It would be easy using sendFile method like this:

def index = Action {
  val fileToServe = TemporaryFile(new java.io.File("/tmp/fileToServe.pdf"))
  Ok.sendFile(content = fileToServe, onClose = () => fileToServe.clean)
}

But I'd like to process the file in a streaming way in order to reduce the memory footprint:

def index = Action {
  val file = new java.io.File("/tmp/fileToServe.pdf")
  val path: java.nio.file.Path = file.toPath
  val source: Source[ByteString, _] = FileIO.fromPath(path)

  Ok.sendEntity(HttpEntity.Streamed(source, Some(file.length()), Some("application/pdf")))
    .withHeaders("Content-Disposition" → "attachment; filename=file.pdf")
}

And in the latter case I can't figure out the moment when the stream would be finished and I will be able to remove the file from filesystem.

1
Use .watchTermination or .mapMaterializedValue on the stream - cchantep

1 Answers

1
votes

You could use watchTermination on the Source to delete the file once the stream has completed. For example:

val source: Source[ByteString, _] =
  FileIO.fromPath(path)
        .watchTermination()((_, futDone) => futDone.onComplete {
          case Success(_) =>
            println("deleting the file")
            java.nio.file.Files.delete(path)
          case Failure(t) => println(s"stream failed: ${t.getMessage}")
        })