Is there a nice, safe, quick way to write an InputStream to a File in Scala?

15,927

Solution 1

If it's a text file, and you want to limit yourself to Scala and Java, then using scala.io.Source to do the reading is probably the fastest--it's not built in, but easy to write:

def inputToFile(is: java.io.InputStream, f: java.io.File) {
  val in = scala.io.Source.fromInputStream(is)
  val out = new java.io.PrintWriter(f)
  try { in.getLines().foreach(out.println(_)) }
  finally { out.close }
}

But if you need other libraries anyway, you can make your life even easier by using them (as Michel illustrates).

(P.S.--in Scala 2.7, getLines should not have a () after it.)

(P.P.S.--in old versions of Scala, getLines did not remove the newline, so you need to print instead of println.)

Solution 2

With Java 7 or later you can use Files from the new File I/O:

Files.copy(from, to)

where from and to can be Paths or InputStreams. This way, you can even use it to conveniently extract resources from applications packed in a jar.

Solution 3

I don't know about any Scala specific API, but since Scala is fully compatible to Java you can use any other library like Apache Commons IO and Apache Commons FileUpload.

Here is some example code (untested):

//using Commons IO:
val is = ... //input stream you want to write to a file
val os = new FileOutputStream("out.txt")
org.apache.commons.io.IOUtils.copy(is, os)
os.close()

//using Commons FileUpload
import javax.servlet.http.HttpServletRequest
import org.apache.commons.fileupload.{FileItemFactory, FileItem}
import apache.commons.fileupload.disk.DiskFileItemFactory
import org.apache.commons.fileupload.servlet.ServletFileUpload
val request: HttpServletRequest = ... //your HTTP request
val factory: FileItemFactory = new DiskFileItemFactory()
val upload = new ServletFileUpload(factory)
val items = upload.parseRequest(request).asInstanceOf[java.util.List[FileItem]]
for (item <- items) item.write(new File(item.getName))

Solution 4

The inputToFile method given above doesn't work well with binary files like .pdf files. It throws a runtime exception while attempting to decode the file into string. What worked for me was this:

def inputStreamToFile(inputStream: java.io.InputStream, file: java.io.File) = {
    val fos = new java.io.FileOutputStream(file)
    fos.write(
      Stream.continually(inputStream.read).takeWhile(-1 !=).map(_.toByte).toArray
    )
    fos.close()
}
Share:
15,927
pr1001
Author by

pr1001

Updated on June 05, 2022

Comments

  • pr1001
    pr1001 almost 2 years

    Specifically, I'm saving a file upload to local file in a Lift web app.

  • Jus12
    Jus12 about 8 years
    Do you need to call close after this?
  • notan3xit
    notan3xit almost 8 years
    Files itself does not represent a file, but is a static collection of I/O functions, so it does not require to be closed. Files.copy does not manipulate the streams you pass in, so whatever you may need to close there, you must close yourself.
  • Grigoriev Nick
    Grigoriev Nick over 4 years
    can't call this method because of ``` Error:(25, 11) overloaded method value copy with alternatives: (x$1: java.nio.file.Path,x$2: java.io.OutputStream)Long <and> (x$1: java.io.InputStream,x$2: java.nio.file.Path,x$3: java.nio.file.CopyOption*)Long <and> (x$1: java.nio.file.Path,x$2: java.nio.file.Path,x$3: java.nio.file.CopyOption*)java.nio.file.Path cannot be applied to (java.io.InputStream, java.io.File) Files.copy(content, distTemporaryFile) ```
  • notan3xit
    notan3xit over 4 years
    It seems that you are passing an File as second argument whereas the functions expects a Path. You could File.toPath() to obtain the Path.