Win a copy of Java Concurrency Live Lessons this week in the Threads forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

Writing input stream to file  RSS feed

 
Aaron John
Ranch Hand
Posts: 74
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I would like to know whether it's possible to write the contents of a ServletInputStream to a file. My JSP page POST's an image, and I want my servlet to write that image to file. How can I do this?

I know how to get the InputStream from the Servlet, but I'm not sure of the code to use the incoming InputStream to write the file. Can anyone help me?
 
Joe Ess
Bartender
Posts: 9406
12
Linux Mac OS X Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
All you need to do is open an output stream (presumably a FileOutputStream in your case), read from the input stream and write to the output stream. Have a look at the Java tutorial chapter on IO. Streams in Java are kind of strange, but once you learn how to read/write one, you can read/write all of them no matter what the source or destination.
 
Aaron John
Ranch Hand
Posts: 74
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the reply. Potentially the POST could be very big. Are there any other IO classes that could perform more efficiently? Unless the FileOutputStream does the job adequately....
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
There are other classes, but it's unlikely they will have significantly different performance in this case. Certain classes and methods in java.nio can be notably faster (notably FileChannel's transferTo() and transferFrom() methods), but only if the source and target both use nio classes almost exclusively. Since you've got an InputStream to start with, you can't really get a significant advantage from using the nio classes here. The Channels class offers some adapters between nio and io, but the efficiency of those adapters is basically the same as you'll get from simply using the FileOutputStream directly. Also the nio classes tend to be harder to understand. I doubt it's worth spending much time exploring the alternatives here - at least, unless and until you can confirm that there really is a performance problem with the FileOutputStream solution.

Really, FileOutputStream works quite well for most applications, even for big files. Just be sure to use the read() and write() methods that take an array of bytes, not just one byte at a time. That's likely to have more impact on speed than changing to other classes would.
 
Aaron John
Ranch Hand
Posts: 74
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the help. Here is the portion of the Servlet code (just two private methods) which receives a ServletInputStream from a request, and writes the content in the file. Is this the correct approach or is there a cleaner way to do this?

 
Paul Clapham
Sheriff
Posts: 22185
38
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Way too much code. And it's fragile, too. If the request doesn't have a content length (because the client didn't send one) then the code fails. If the content length is very large (because the uploaded file is very large) then you run out of memory. And it's unlikely that your first call to is.read() is actually going to read the entire upload, if the content length is fairly large, and your code arbitrarily rejects that too.

I would use simple code like this:You could experiment with wrapping those streams in BufferedInputStream and BufferedOutputStream and see if that makes a difference.
 
Aaron John
Ranch Hand
Posts: 74
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you for simplifying the code. I have one more question. How does specifying a fixed buffer size help here, especially when you have a big file to read and write? Excuse my IO knowledge, it is very poor.
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
[Paul C]: And it's unlikely that your first call to is.read() is actually going to read the entire upload, if the content length is fairly large, and your code arbitrarily rejects that too.

I don't believe that's true here - Aaron's code does seem to keep reading until either the content length is reached, or an EOF is returned. Assuming the content length is set correctly (not always true, as noted) then it will never actually read the EOF. Still, I agree with all your other points.

[Aaron]: How does specifying a fixed buffer size help here, especially when you have a big file to read and write?

The primary benefit is as Paul noted - it uses less memory (at least for large files) because you don't have to store the entire file in memory at once. Also most IO doesn't occur all at once anyway - the servlet is probly getting the request data in chunks, as it receives packets, and the FileOutputStream may well be writing in chunks too as limited by a hardwaree buffer somewhere. The idea here is to grab whatever data is available, as soon as it's available, and transfer it - rather than waiting for all the data to become available. Thus this is generally a little more efficient, doing some disk writing while the network is still transferring bytes to the server.

One other thing: I usually recommend putting all close() operations in a finally block. This ensures that a stream is closed promptly even if an exception occurs. This doesn't really matter, say, 99% of the time or more, but in the remaining 1% or so it can help prevent some confusing errors. Especially if you plan to move or delete any files when you're done with them - an open FileInputStream or FileOutputStream can cause delete() or renameTo() to fail inexplicably. (That is, it's explicable only if you realize that there's an unclosed stream somewhere.) These are a pain to debug, and so I usually am very religious about making sure streams get closed after they're used. So my version of this code would be:
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Also, the exact value used for the buffer size doesn't usually matter a great deal - powers of 2 are generally preferred, but in my experience anything more than a few thousand generally gives pretty similar results. If you're really curious you can test on your system to see what values provide the best results - but beware that if you put your code on a different box, you may get different results. I usually use 4096 or 8192, depending on my mood, and don't worry about it otherwise unless testing reveals a performance problem. (Which thus far hasn't led me to revisit my buffer size.) If you've got a shortage of memory you can certainly use a smaller buffer, but it may be slightly slower.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!