I know that there are a couple of similarly entitled questions out there, but most of them have simply forgotten to put a close() directive on their stream. This here is different.
Lets say I have the following minimal example:
public void test() throws IOException
{
InputStream in;
if( file.exists() )
{
in = new FileInputStream( file );
}
else
{
in = new URL( "some url" ).openStream();
}
in.close();
}
This give me a Resource leak: 'in' is never closed warning in Eclipse (Juno SR1).
But when I move the in.close() into the conditional block, the warnings vanishes:
public void test() throws IOException
{
InputStream in;
if( file.exists() )
{
in = new GZIPInputStream( new FileInputStream( file ) );
in.close();
}
else
{
in = new URL( "some URL" ).openStream();
}
}
What is going on here?
Because of the IO exception, you can run into a resource leak (poentially)
Try doing the following:
public void test() throws IOException
{
InputStream in= null;
try {
if( file.exists() )
{
// In this case, if the FileInputStream call does not
// throw a FileNotFoundException (descendant of IOException)
// it will create the input stream which you are wrapping
// in a GZIPInputStream (no IO exception on construction)
in = new GZIPInputStream( new FileInputStream( file ) );
}
else
{
// Here however, if you are able to create the URL
// object, "some url" is a valid URL, when you call
// openStream() you have the potential of creating
// the input stream. new URL(String spec) will throw
// a MalformedURLException which is also a descendant of
// IOException.
in = new URL( "some url" ).openStream();
}
// Do work on the 'in' here
} finally {
if( null != in ) {
try
{
in.close();
} catch(IOException ex) {
// log or fail if you like
}
}
}
}
Doing the above will make sure you've closed the stream or at least made a best effort to do so.
In your original code, you had the InputStream declared but never initialized. That is bad form to begin with. Initialize that to null as I illustrated above. My feeling, and I'm not running Juno at the moment, is that it sees that the InputStream 'in', may potentially make it through all the hoops and hurdles to get to the point at which you are going to use it. Unfortunate, as someone pointed out, your code is a bit dodgy for an example. Doing this as I've detailed as well as #duffymo you'll get rid of the warning.
Here's how I'd write it:
public void test() throws IOException
{
InputStream in = null;
try {
if(file.exists()) {
in = new FileInputStream( file );
} else {
in = new URL( "some url" ).openStream();
}
// Do something useful with the stream.
} finally {
close(in);
}
}
public static void close(InputStream is) {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
I suspect the warning is incorrect. It could be checking you are closing the stream in the same scope. In the second case, you are not closing the second stream.
Your in stream may not be initialized if the file doesn't exist and you try to close a non-existent file.
Your second example would also need a close statement to avoid leaks.
This same Eclipse reporting can happen when you explicitly throw an exception after you have opened your resource like:
public void method() throws IOException {
BufferedReader br = new BufferedReader(new FileReader("myfile.txt"));
while (br.ready()) {
String line = br.readLine():
if (line.length() > 255) {
throw new IOException("I am some random IOException");
}
}
br.close();
}
This is some contrived code for demonstration purposes so don't look too hard.
If one were to comment out the line, the warning goes away. Of course, you instead want to make sure that that resource is being closed properly. You could do:
if (line.length() > 255) {
br.close();
throw new IOException("I am some random IOException");
}
Do not rely on the Eclipse warnings in this case though. Get in the habit of using the try/finally approach to make sure that resources are correctly and consistently being closed.
I have something like:
InputStream content = httpResponse.getEntity()==null?null:httpResponse.getEntity().getContent();
that gives the same warrning. But if I leave it just like this:
InputStream content =httpResponse.getEntity().getContent();
I receive no warrnings. Isn't strange or what?
-- I hope my info is adding knowledge to the original question. Thanks!
Related
I wrote a simple java function that reads a file of Floating-point values and in the case file is not found or
the values that are being read are not floating-point the program throws exceptions.
My question is on the case that the program opened the file but the format of values was not floating-point - can the program close the resources? or should I consider the runtime exception that may happen?
public static ArrayList<Double> readValues(String filename) throws
FileNotFoundException {
var file = new File(filename);
var fileScanner = new Scanner(file);
var doubleList = new ArrayList<Double>();
//In case the values are not of double type and the scanner
while(fileScanner.hasNext())
doubleList.add( Double.parseDouble( fileScanner.next() ) );
fileScanner.close();
return doubleList;
}
o.k I updated the code to use in 'finally' statement
public static ArrayList<Double> readValues(String filename) throws
FileNotFoundException {
var file = new File(filename);
var fileScanner = new Scanner(file);
var doubleList = new ArrayList<Double>();
//In case the values are not of double type and the scanner
try {
while(fileScanner.hasNext())
doubleList.add( Double.parseDouble( fileScanner.next() ) );
}finally {
fileScanner.close();
}
return doubleList;
}
If there are better ideas, I would like to know.
Thanks for the help
Java finally block is always executed whether exception is handled or not.
Please refer to this
A standard approch
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(...);
// do something with the inputstream
} catch (IOException e) {
// handle an exception
} finally { // finally blocks are guaranteed to be executed
// close() can throw an IOException too, so we got to wrap that too
try {
if (fileInputStream != null) {
fileInputStream.close();
}
} catch (IOException e) {
// handle an exception, or often we just ignore it
}
}
From java7: The try-with-resources Statement
From the oracle docs Refer here
You can close resources by using try with resources
try(// open resources here){
// use resources
} catch (FileNotFoundException e) {
// exception handling
}
// resources are closed as soon as try-catch block is executed.
Below is the code Snippet.
FileInputStream fin = new FileInputStream(zipFile);
ZipInputStream zin = new ZipInputStream(fin);
ZipEntry entry = null;
String routerListUCM = "";
try {
entries:
while ((entry = zin.getNextEntry()) != null) {
if (entry.getName().startsWith("routes")) {
BufferedReader in = new BufferedReader(new InputStreamReader(zin, "UTF-8"));
if (true) {
//parse the xml of the route...
DOMParser dp = new DOMParser();
dp.parse(in);
Element e = (Element) dp.getDocument().getFirstChild();
String transferid = e.getElementsByTagName("transferId").item(0).getTextContent();
System.out.println("transferId=" + transferid);
int fileid = Integer.parseInt(transferid.split("-")[1]);
System.out.println("fileid=" + transferid);
String userList = e.getElementsByTagName("userList").item(0).getTextContent();
System.out.println("userList=" + userList);
String routeList = e.getElementsByTagName("routeList").item(0).getTextContent();
System.out.println("routeList=" + routeList);
routerListUCM = routeList;
if (routeList.toLowerCase().indexOf(myname().toLowerCase()) == -1) {
//my server is not in the current route...
//so skip this route table.
continue entries;
}
}
}
}
} catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace();
}
in some cases after "continue entries;" and trying for next loop i see "stream close Exception" :/
error:Stream closed
Stack Trace:
java.io.IOException: Stream closed
at java.util.zip.ZipInputStream.ensureOpen(ZipInputStream.java:67)
at java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:116)
at org.parsisys.test.mina.view.SimpleFtplet$beaVersion0_1155.isTransferFinished(SimpleFtplet.java:299)
at org.parsisys.test.mina.view.SimpleFtplet.isTransferFinished(SimpleFtplet.java)
at org.parsisys.test.mina.view.SimpleFtplet.beaAccessisTransferFinished(SimpleFtplet.java)
at org.parsisys.test.mina.view.SimpleFtplet$beaVersion0_1155.onUploadEnd(SimpleFtplet.java:208)
at org.parsisys.test.mina.view.SimpleFtplet.onUploadEnd(SimpleFtplet.java)
at org.apache.ftpserver.ftplet.DefaultFtplet.afterCommand(DefaultFtplet.java:89)
at org.parsisys.test.mina.view.SimpleFtplet.afterCommand(SimpleFtplet.java)
at org.apache.ftpserver.ftpletcontainer.impl.DefaultFtpletContainer.afterCommand(DefaultFtpletContainer.java:144)
at org.apache.ftpserver.impl.DefaultFtpHandler.messageReceived(DefaultFtpHandler.java:220)
at org.apache.ftpserver.listener.nio.FtpHandlerAdapter.messageReceived(FtpHandlerAdapter.java:61)
at org.apache.mina.core.filterchain.DefaultIoFilterChain$TailFilter.messageReceived(DefaultIoFilterChain.java:716)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(DefaultIoFilterChain.java:434)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.access$1200(DefaultIoFilterChain.java:46)
at org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.messageReceived(DefaultIoFilterChain.java:796)
at org.apache.ftpserver.listener.nio.FtpLoggingFilter.messageReceived(FtpLoggingFilter.java:85)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(DefaultIoFilterChain.java:434)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.access$1200(DefaultIoFilterChain.java:46)
at org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.messageReceived(DefaultIoFilterChain.java:796)
at org.apache.mina.core.filterchain.IoFilterEvent.fire(IoFilterEvent.java:75)
at org.apache.mina.filter.logging.MdcInjectionFilter.filter(MdcInjectionFilter.java:136)
at org.apache.mina.filter.util.CommonEventFilter.messageReceived(CommonEventFilter.java:70)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(DefaultIoFilterChain.java:434)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.access$1200(DefaultIoFilterChain.java:46)
at org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.messageReceived(DefaultIoFilterChain.java:796)
at org.apache.mina.filter.codec.ProtocolCodecFilter$ProtocolDecoderOutputImpl.flush(ProtocolCodecFilter.java:427)
at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecFilter.java:245)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(DefaultIoFilterChain.java:434)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.access$1200(DefaultIoFilterChain.java:46)
at org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.messageReceived(DefaultIoFilterChain.java:796)
at org.apache.mina.core.filterchain.IoFilterEvent.fire(IoFilterEvent.java:75)
at org.apache.mina.core.session.IoEvent.run(IoEvent.java:63)
at org.apache.mina.filter.executor.OrderedThreadPoolExecutor$Worker.runTask(OrderedThreadPoolExecutor.java:780)
at org.apache.mina.filter.executor.OrderedThreadPoolExecutor$Worker.runTasks(OrderedThreadPoolExecutor.java:772)
at org.apache.mina.filter.executor.OrderedThreadPoolExecutor$Worker.run(OrderedThreadPoolExecutor.java:714)
at java.lang.Thread.run(Thread.java:748)
Please Help Me....................................................................................................................................................................................................................................................
It seems that your outermost BufferedReader object closes your nested streams (in particular ZipInputStream). Try to move your BufferedReader initalization code higher the looping logic.
Also this topic might be helpful: closing nested streams.
Update:
Ok, now everything is clear. Implementation code of DOMParser class shows clearly that parse method closes underlying InputStream source (just an excerpt of finally block):
} finally {
this.parser.reader.close();
}
What can be done in this situation is hacking your BufferedReader which is passed to DOMParser object. Here's an example:
public class HackedReader extends BufferedReader {
public HackedReader(InputStreamReader inputStreamReader) {
super(inputStreamReader);
}
#Override
public void close() {
// Close method doesn't do anything, that's the main sense of overriding.
}
// But you know exact method which will close your underlying stream.
public void hackedClose() throws IOException {
super.close();
}
}
I found using the org.apache.poi.util.CloseIgnoringInputStream worked for me. I was able to wrap the ZipInputStream that I was passing into another method.
For example:
ExcelUtility.getLineCount(new CloseIgnoringInputStream(zipStream)
If you can implemet a logic to understand if there aren't more "routes" to read, at the end of If block you can insert a break instruction to exit the while block and avoid to attempt to read the closed stream
So in some method, I will be opening a new IO stream, doing some processing with it, and then using that stream as the input to open up another IO stream. I don't believe I can use a single try-with-resources block because of the processing with the first IO stream being in between opening the first and second streams. So with that said, would it be better (in a coding-design sense) to use a single try-catch-finally block to open and close these streams or use nested try-with-resources blocks to open and close the streams? I know that if there is no processing between the first and second IO streams, it would be best to open all three streams in a single try-with-resources block.
A simplistic example follows:
Try-Catch-Finally
void someMethod(InputStream is) throws SomeException {
SomeIOStream io1 = null;
SomeIOStream io2 = null;
SomeIOStream io3 = null;
try{
io1 = new SomeIOStream( someSortOfProcessing() );
io1.moreStreamProcessing();
io2 = new SomeIOStream( someSortOfProcessing(io1) );
io3 = new SomeIOStream (is);
//do stuff with io2 and io3
} catch (Throwable t) {
//Exception Handling
} finally {
//closing streams io3, io2, io1, is
}
}
Try-with-resources
void someMethod(InputStream is) throws SomeException {
try ( SomeIOStream io1 = new SomeIOStream( someSortOfProcessing() ) ){
io1.moreStreamProcessing();
try ( SomeIOStream io2 = new SomeIOStream( someSortOfProcessing(io1) );
SomeIOStreeam io3 = new SomeIOStream (is); ){
//do stuff with io2 and io3
}
} catch (Throwable t) {
//Exception Handling
} finally {
//closing stream is
}
}
To me, it looks as though the first is cleaner, but the second has the benefits of a try-with-resources block. Of course, another alternative is to open the initial io1 with try-with-resources, but open io2 and io3 within that try-block. So would this third mixed approach be better than the above two?
Mixed Approach
void someMethod(InputStream is) throws SomeException {
SomeIOStream io1 = null;
SomeIOStream io2 = null;
SomeIOStream io3 = null;
try (SomeIOStream io1 = new SomeIOStream( someSortOfProcessing() ) ){
io1.moreStreamProcessing();
io2 = new SomeIOStream( someSortOfProcessing(io1) );
io3 = new SomeIOStream (is);
//do stuff with io2 and io3
} catch (Throwable t) {
//Exception Handling
} finally {
//closing streams io3, io2, is
}
}
Also as an additional question, am I right to assume that the only way to close the InputStream is would be to put it in the finally-block?
It seems, you are not aware, what the try with resources does for you. It does not only ensure that close() gets called, it also ensures that in the case that close() fails with an exception, it won’t shadow the initial exception, if there is one, but instead, record the secondary exception using addSuppressed.
So the equivalent of
try(Resource r = allocation ) {
…
}
is
{
Resource r = allocation;
Throwable primary = null;
try {
…
}
catch(Throwable t) { primary = t; }
finally {
if(r != null) try {
r.close();
}
catch(Throwable t) {
if(primary!=null) primary.addSuppressed(t); else primary=t;
}
}
if(primary!=null) throw primary;
}
Now think again whether rewriting any of the try with resources statements, to do this manually, creates cleaner code. Even without handling the close correctly, your alternatives to the nested try with resource statements are already bigger in code size, more complicated and expanding the scope of variables beyond their actual use.
In contrast, the nested try with resource statements reflect exactly what you are doing, using resources in a nested scope. It will become even better, if you remove the questionable catch-all part and the closing of the incoming resource.
Note that in rare circumstances, closing the incoming resource might be acceptable, e.g. if it is a private method and the behavior is well-documented. But even then, you should not resort to finally:
void someMethod(InputStream incomingIs) throws SomeException {
try(InputStream is=incomingIs;// it must be documented that we will close incomingIs
SomeIOStream io1 = new SomeIOStream(someSortOfProcessing()) ) {
io1.moreStreamProcessing();
try(SomeIOStream io2 = new SomeIOStream(someSortOfProcessing(io1));
SomeIOStreeam io3 = new SomeIOStream (is) ) {
//do stuff with io2 and io3
}
}
}
It's probably opinion-based, but I would certainly prefer using try-with-resources as much as possible. This clearly shows the scope of the closeable resource usage making the program logic easier to understand. If you worry about nested try-with-resources blocks, consider extracting the inner block into the separate method.
Also if you have the stream passed as parameter (is in your example), it's usually not a good idea to close it. If caller created this stream, it's usually caller's responsibility to close it (preferably with try-with-resource statement in caller method). Finally it's rarely good idea to catch the Throwable.
I am writing a piece of code:
OutputStream outputStream = new FileOutputStream(createdFile);
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(gzipOutputStream));
Do I need to close every stream or writer like the following?
gzipOutputStream.close();
bw.close();
outputStream.close();
Or will just closing the last stream be fine?
bw.close();
Assuming all the streams get created okay, yes, just closing bw is fine with those stream implementations; but that's a big assumption.
I'd use try-with-resources (tutorial) so that any issues constructing the subsequent streams that throw exceptions don't leave the previous streams hanging, and so you don't have to rely on the stream implementation having the call to close the underlying stream:
try (
OutputStream outputStream = new FileOutputStream(createdFile);
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
OutputStreamWriter osw = new OutputStreamWriter(gzipOutputStream);
BufferedWriter bw = new BufferedWriter(osw)
) {
// ...
}
Note you no longer call close at all.
Important note: To have try-with-resources close them, you must assign the streams to variables as you open them, you cannot use nesting. If you use nesting, an exception during construction of one of the later streams (say, GZIPOutputStream) will leave any stream constructed by the nested calls inside it open. From JLS §14.20.3:
A try-with-resources statement is parameterized with variables (known as resources) that are initialized before execution of the try block and closed automatically, in the reverse order from which they were initialized, after execution of the try block.
Note the word "variables" (my emphasis).
E.g., don't do this:
// DON'T DO THIS
try (BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(
new GZIPOutputStream(
new FileOutputStream(createdFile))))) {
// ...
}
...because an exception from the GZIPOutputStream(OutputStream) constructor (which says it may throw IOException, and writes a header to the underlying stream) would leave the FileOutputStream open. Since some resources have constructors that may throw and others don't, it's a good habit to just list them separately.
We can double-check our interpretation of that JLS section with this program:
public class Example {
private static class InnerMost implements AutoCloseable {
public InnerMost() throws Exception {
System.out.println("Constructing " + this.getClass().getName());
}
#Override
public void close() throws Exception {
System.out.println(this.getClass().getName() + " closed");
}
}
private static class Middle implements AutoCloseable {
private AutoCloseable c;
public Middle(AutoCloseable c) {
System.out.println("Constructing " + this.getClass().getName());
this.c = c;
}
#Override
public void close() throws Exception {
System.out.println(this.getClass().getName() + " closed");
c.close();
}
}
private static class OuterMost implements AutoCloseable {
private AutoCloseable c;
public OuterMost(AutoCloseable c) throws Exception {
System.out.println("Constructing " + this.getClass().getName());
throw new Exception(this.getClass().getName() + " failed");
}
#Override
public void close() throws Exception {
System.out.println(this.getClass().getName() + " closed");
c.close();
}
}
public static final void main(String[] args) {
// DON'T DO THIS
try (OuterMost om = new OuterMost(
new Middle(
new InnerMost()
)
)
) {
System.out.println("In try block");
}
catch (Exception e) {
System.out.println("In catch block");
}
finally {
System.out.println("In finally block");
}
System.out.println("At end of main");
}
}
...which has the output:
Constructing Example$InnerMost
Constructing Example$Middle
Constructing Example$OuterMost
In catch block
In finally block
At end of main
Note that there are no calls to close there.
If we fix main:
public static final void main(String[] args) {
try (
InnerMost im = new InnerMost();
Middle m = new Middle(im);
OuterMost om = new OuterMost(m)
) {
System.out.println("In try block");
}
catch (Exception e) {
System.out.println("In catch block");
}
finally {
System.out.println("In finally block");
}
System.out.println("At end of main");
}
then we get the appropriate close calls:
Constructing Example$InnerMost
Constructing Example$Middle
Constructing Example$OuterMost
Example$Middle closed
Example$InnerMost closed
Example$InnerMost closed
In catch block
In finally block
At end of main
(Yes, two calls to InnerMost#close is correct; one is from Middle, the other from try-with-resources.)
You can close the outer most stream, in fact you don't need to retain all the streams wrapped and you can use Java 7 try-with-resources.
try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new GZIPOutputStream(new FileOutputStream(createdFile)))) {
// write to the buffered writer
}
If you subscribe to YAGNI, or you-aint-gonna-need-it, you should be only adding code you actually need. You shouldn't be adding code you imagine you might need but in reality doesn't do anything useful.
Take this example and imagine what could possibly go wrong if you didn't do this and what the impact would be?
try (
OutputStream outputStream = new FileOutputStream(createdFile);
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
OutputStreamWriter osw = new OutputStreamWriter(gzipOutputStream);
BufferedWriter bw = new BufferedWriter(osw)
) {
// ...
}
Lets start with FileOutputStream which calls open to do all the real work.
/**
* Opens a file, with the specified name, for overwriting or appending.
* #param name name of file to be opened
* #param append whether the file is to be opened in append mode
*/
private native void open(String name, boolean append)
throws FileNotFoundException;
If the file is not found, there is no underlying resource to close, so closing it won't make any difference. If The file exists, it should be throwing a FileNotFoundException. So there is nothing to be gained by trying to close the resource from this line alone.
The reason you need to close the file is when the file is opened successfully, but you later get an error.
Lets look at the next stream GZIPOutputStream
There is code which can throw an exception
private void writeHeader() throws IOException {
out.write(new byte[] {
(byte) GZIP_MAGIC, // Magic number (short)
(byte)(GZIP_MAGIC >> 8), // Magic number (short)
Deflater.DEFLATED, // Compression method (CM)
0, // Flags (FLG)
0, // Modification time MTIME (int)
0, // Modification time MTIME (int)
0, // Modification time MTIME (int)
0, // Modification time MTIME (int)
0, // Extra flags (XFLG)
0 // Operating system (OS)
});
}
This writes the header of the file. Now it would be very unusual for you to be able to open a file for writing but not be able to write even 8 bytes to it, but lets imagine this could happen and we don't close the file afterwards. What does happen to a file if it is not closed?
You don't get any unflushed writes, they are discarded and in this case, there is no successfully written bytes to the stream which isn't buffered at this point anyway. But a file which is not closed doesn't live forever, instead FileOutputStream has
protected void finalize() throws IOException {
if (fd != null) {
if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
flush();
} else {
/* if fd is shared, the references in FileDescriptor
* will ensure that finalizer is only called when
* safe to do so. All references using the fd have
* become unreachable. We can call close()
*/
close();
}
}
}
If you don't close a file at all, it gets closed anyway, just not immediately (and like I said, data which is left in a buffer will be lost this way, but there is none at this point)
What is the consequence of not closing the file immediately? Under normal conditions, you potentially lose some data, and you potentially run out of file descriptors. But if you have a system where you can create files but you can't write anything to them, you have a bigger problem. i.e. it hard to imagine why you are repeatedly trying to create this file despite the fact you are failing.
Both OutputStreamWriter and BufferedWriter don't throw IOException in their constructors, so it not clear what problem they would cause. In The case of BufferedWriter, you could get an OutOfMemoryError. In this case it will immediately trigger a GC, which as we have seen will close the file anyway.
If all of the streams have been instantiated then closing only the outermost is just fine.
The documentation on Closeable interface states that close method:
Closes this stream and releases any system resources associated with it.
The releasing system resources includes closing streams.
It also states that:
If the stream is already closed then invoking this method has no effect.
So if you close them explicitly afterwards, nothing wrong will happen.
I'd rather use try(...) syntax (Java 7), e.g.
try (OutputStream outputStream = new FileOutputStream(createdFile)) {
...
}
It will be fine if you only close the last stream - the close call will be send to the underlying streams, too.
No, the topmost level Stream or reader will ensure that all underlying streams / readers are closed.
Check the close() method implementation of your topmost level stream.
In Java 7, there is a feature try-with-resources. You no need to explicitly close your streams, it will take care of that.
I have a Servlet in Tomcat 5.5 that reads local images sitting on a folder. The image is then sent back to an Applet.
I'm getting this "javax.imageio.IIOException: Can't create an ImageInputStream!" error and not sure whats causing it.
Has anyone had this problem before? Could this be a Thread issue in the ImageIO? I can't reproduce this issue since it occurs about 3 times for every 1000 requests.
EDIT: This is the Servlet code that reads the image. I just use the ImageIO.read(File) in its static form inside the Servlet's doPost method the same way below:
doPost(req,resp){
...
BufferedImage image = ImageIO.read(imageFile);
...
}
Here is the source code for javax.imageio.ImageIO.read(File):
public static BufferedImage read(File input) throws IOException {
if (input == null) {
throw new IllegalArgumentException("input == null!");
}
if (!input.canRead()) {
throw new IIOException("Can't read input file!");
}
ImageInputStream stream = createImageInputStream(input);
if (stream == null) {
throw new IIOException("Can't create an ImageInputStream!");
}
BufferedImage bi = read(stream);
if (bi == null) {
stream.close();
}
return bi;
}
If the sole functional requirement is to read images from local disk and return it unmodified to the HTTP response using a servlet, then you do not need the ImageIO at all. It only adds unnecessary overhead and other problems like you're having now.
Get rid of the ImageIO stuff and just stream the raw image straight from disk to HTTP response, along a set of proper response headers. For example,
String name = request.getParameter("name");
File file = new File("/path/to/images", name);
response.setContentType(getServletContext().getMimeType(file.getName()));
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\"");
InputStream input = null;
OutputStream output = null;
try {
input = new BufferedInputStream(new FileInputStream(file));
output = new BufferedOutputStream(response.getOutputStream());
byte[] buffer = new byte[8192];
for (int length; (length = input.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
} finally {
if (output != null) try { output.close(); } catch (IOException logOrIgnore) {}
if (input != null) try { input.close(); } catch (IOException logOrIgnore) {}
}
That's all. You only need ImageIO whenever you would like to manipulate the image in server's memory before returning it, e.g. resizing, transforming or something.
Another, more robust, example of such a servlet can be found here and a more advanced one here.
The source I have (Java5 but I doubt it has changed a lot) states that if there are no ImageInputStream service providers registered, the createImageInputStream method returns null and thus you get that exception.
From the JavaDoc on IIORegistry.getDefaultInstance() which is used by ImageIO:
Each ThreadGroup will receive its own instance; this allows different Applets in the same browser (for example) to each have their own registry.
Thus it might actually be a threading problem in that you get a plain new instance of IIORegistry.
Edit: digging deeper into the source I found the following:
Most likely you'd get a FileImageInputStream, since you pass in a file. However, if an exception occurs the service provider returns null. Thus there might be a FileNotFoundException or any other IOException being thrown which causes the stream not to be created.
Unfortunately, there's no logging in the code, thus you'd have to debug somehow. It's probably due to missing file permissions, a corrupted/incomplete file or the file missing.
Here's the Java5 source for FileImageInputStreamSpi#createInputStreamInstance()
public ImageInputStream createInputStreamInstance(Object input,
boolean useCache,
File cacheDir) {
if (input instanceof File) {
try {
return new FileImageInputStream((File)input);
} catch (Exception e) {
return null;
}
} else {
throw new IllegalArgumentException();
}
}
Where is your use of close() methods within the exception handling? Streams have to be closed when there are exceptions, too, as well as normal termination of the block of the code.
The symptom sounds like you run out of heap space or sometime.
It is not the coding errors that others pointed out, since the problem is intermittent.