3

I will be performing a lecture on Java for students of Physics, and I would like to know how to properly open a file.

In many my proffesional apps I did somethings like that:

  BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("file")));
  try{
    ....
  }finally {
     bufferedWriter.close();
  }

which is IMHO ok, i.e. reader will allways be closed.

When I was putting that in example for my students I was wondering what will happen if constructor of InputStreamReader will throw an exception --- FileInputStream will be open, but it will not be closed by my code (since these objects are created outside try-finally block.

So is this right idiom, and if so then why? If it is not right idiom to open a stream please point me the right one!

Edit: I'm looking for idiom that is both correct and very easy to write and understand, physics students are beginners in programming.

Edit: Silly me I copied wrong example --- if instead of Readers I use Writers it get's more complicated.

jb.
  • 23,300
  • 18
  • 98
  • 136

2 Answers2

4

Reading with input streams

Prior to Java 7 this is how you'd do it

InputStream in = null;
try {
     in = new FileInputStream("simple.csv");
     BufferedReader buf = new BufferedReader(new InputStreamReader(in));
} finally {
  if (in != null) {
     try {
         in.close();
     } catch (IOException e) {}
  }
}

For Java 7 you can use Closeable, something like

try (BufferedReader buf = new BufferedReader(...)) {}

EDIT: Why didn't I close buf above? Have a look at the source code for BufferedReader.close()

public void close() throws IOException {
    synchronized (lock) {
        if (in == null)
            return;
        in.close();
        in = null;
        cb = null;
    }
}

Writing with output streams

EDIT 2: The same principle applies to writers. However if you're really interested in flushing a stream when the IOException occurs, then you must check both the writer and the stream for null and try tro close them respectively. That though, gives a lot of extra code. It could look something like this:

BufferedWriter buf = null;
OutputStream out = null;
try {
    out = new FileOutputStream("file");
    buf = new BufferedWriter(new OutputStreamWriter(out));
} finally {
  if (buf != null) {
     try { buf.close(); } catch (IOException ex){}
  }
  if (out != null) {
     try { out.close(); } catch (IOException ex){}
  }
}

It's not very pretty. You could introduce a helper routine to close your streams or look into either Java 7 or Apache IOUtils

Johan Sjöberg
  • 47,929
  • 21
  • 130
  • 148
  • not quite...... (edit: never mind, you've fixed both my objections. I'd use `BufferedReader buf = null` just to be explicit) – Jason S Mar 31 '12 at 20:22
  • This won't close the stream if `InputStreamReader` will throw an exception. You will also eventually cause another `NullPointerException`, because `buf` might be `null` here. – Neet Mar 31 '12 at 20:24
  • @RenéJeschke, thanks for noticing, I wasn't detailed oriented enough, I will fix it. – Johan Sjöberg Mar 31 '12 at 20:25
  • @jb. correct. Unless you want to reuse the buffered reader I see no point in doing it. You can of course, just in the same manner that `in` is being tested and closed. – Johan Sjöberg Mar 31 '12 at 20:37
  • AFAIK there is --- because before close buffers are flushed. – jb. Mar 31 '12 at 20:39
  • Yes! I pasted wrong example --- if you use writers instead of readers You migjt need to close all items in chain, or I'm wrong? – jb. Mar 31 '12 at 20:44
  • Yes that's right. However, do you *really* want to flush if an `IOException` occured? – Johan Sjöberg Mar 31 '12 at 20:46
0

In this special case (nested constructors) the FileInputStream will stay open. You will have to do it like this (if you really need to assure the stream gets closed):

final FileInputStream fis = new FileInputStream("");
try
{
    final BufferedReader br = new BufferedReader(new InputStreamReader(fis));
    // ...
}
finally
{
    fis.close();
}

Closing the FileInputStream should be sufficient.

Edit: The same logic can be applied to writers. If opening the FileOutputStream fails, it throws an exception which prevents the try/finally block from execution. And if any other writer constructor fails, the output stream still gets closed through the final clause.

Neet
  • 3,937
  • 15
  • 18
  • Really I just need to find correct code example, and I'm not sure whether extra lines of code to check errors in FileInputStream constructor are worth the effort. – jb. Mar 31 '12 at 20:34
  • On the other hand, the only place where we would expect an exception is the constructor of `FileInputStream` because the file it wants to open might not be existent. – Neet Mar 31 '12 at 20:37