Java, closing inline streams - java

Edit: forgot to mention I'm using java 6
I was wondering about how to close resources in java.
See, I always have initialized streams like this:
ZipInputStream zin = null;
try {
zin = new ZipInputStream(new BufferedInputStream(new FileInputStream(file)));
// Work with the entries...
// Exception handling
} finally {
if (zin!=null) { try {zin.close();} catch (IOException ignored) {} }
}
But, if an exception is thrown in new ZipInputStream(...), would the opened streams in new BufferedInputStream and underliying FileInputStream be leaked?
If they are, what would be the most efficient way to ensure the resources are closed?, should I have to keep a reference to each new ...Stream and close them also in the finally block?, or should the final stream (ZipInputStream in this case) instantiated in some other way?.
Any comments are welcome.

You can do
try (InputStream s1 = new FileInputStream("file");
InputStream s2 = new BufferedInputStream(s1);
ZipInputStream zin = new ZipInputStream(s2)) {
// ...
} catch (IOException e) {
// ...
}
Further reading: The Java™ Tutorials: The try-with-resources Statement.

It can be done in this way:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
try {
ZipInputStream zin = new ZipInputStream(bis);
try {
zin = ;
// Work with the entries...
// Exception handling
} finally {
zin.close();
}
} finally {
bis.close();
}
And you can add error caching where you want.

First lets take a look at what you have and what can go wrong with it:
try {
zin = new ZipInputStream(new BufferedInputStream(new FileInputStream(file)));
// Work with the entries...
// Exception handling
} finally {
if (zin!=null) { try {zin.close();} catch (IOException ignored) {} }
}
a.) new FileInputStream() throws, zin will not be assigned. Nothing to close in this case. Ok.
b.) new BufferedInputStream() throws (possibly OutOfMemoryError), zin not assigned. Leaked FileInputStream(). Bad.
c.) new ZipInputStream() throws, zin will not be assigned. BufferedInputStream and FileInputStream to close. Closing either would be enough. Bad.
Whenever you wrap one stream into another, you are in danger of leaking the stream youre wrapping. You need to have a reference to it and close it somewhere.
A viable way top this is to declare a single InputStream variably to hold the last create stream (or in other words, the outermost of the nested streams):
InputStream input = null;
try {
input = new FileInputStream(...);
input = new BufferedInputStream(input);
input = new ZipInputStream(input);
ZipInputStream zin = (ZipInputStream) input;
// work here
} finally {
if (input != null)
try { input.close(); } catch (IOException ignored) {}
}
This works, because if any of the new *Stream() throws, the variable input is still keeping track of the stream created before. The ugly cast from input to ZipInputStream is necessary, because you must declare input to be a type assignment compatible to all streams created.

Yes, an Exception in new ZipInputStream() or new BufferedInputStream() would leak the enclosed Streams, unless you do a cascading check in the exception handling:
FileInputStream fin = null;
BufferedInputStream bin = null;
ZipInputStream zin = null;
try {
fin = new FileInputStream(file);
bin = new BufferedInputStream(fin)
zin = new ZipInputStream(bin);
// Work with the entries...
// Exception handling
} finally {
try {
if (zin!=null) {
zin.close();
} else if (bin != null) {
bin.close();
} else if (fin != null) {
fin.close();
}
} catch (Exception e) {
// ignore
}
}
However, since BufferedInputStream and ZipInputStream are mere wrapper around the FileInputStream the probability of an Exception is rather low. If at all, an Exception if most likely to happen once you start reading and processing data. And in that case zin is created, and a zin.close() will suffice.

Related

Error where FileOutputStream only writes to file after the program has been terminated

I've had this error in the past but never fully understood it. After closing an OutputStream, regardless of the location of the java file or the manner in which it is called, completely screws up all sequential runs or attempts to write to another file, even if a different method of writing to a file is used. For this reason I avoid closing streams even though it is a horrible habit not to. In my program, I created was trying a test case that had a close statement which destroyed all of my previous streams, making it for some reason that they only write to files after the program has been terminated.
I kept the file location open and it writes the Text in the text file at the appropriate time, however the "Preview" panel in Windows does not detect it (which used to happen). Note that this all worked perfectly before the stream was accidentally closed. Is there a manner to reset the stream? I've tried flushing it during the process but is still does not run as it did prior.
Here is the method used to create the file:
protected void createFile(String fileName, String content) {
try {
String fileLoc = PATH + fileName + ".txt";
File f = new File(fileLoc);
if(!f.isFile())
f.createNewFile();
FileOutputStream outputStream = new FileOutputStream(fileLoc);
byte[] strToBytes = content.getBytes();
outputStream.write(strToBytes);
} catch (IOException e) {
e.printStackTrace();
return;
}
}
as well as the method used to read the file:
protected String readFile(String fileName) {
try {
StringBuilder sb = new StringBuilder("");
String fileLoc = PATH + fileName + ".txt";
File f = new File(fileLoc);
if(!f.exists())
return "null";
Scanner s = new Scanner(f);
int c = 0;
while(s.hasNext()) {
String str = s.nextLine();
sb.append(str);
if(s.hasNext())
sb.append("\n");
}
return sb.toString();
} catch(Exception e) {
e.printStackTrace();
return "null";
}
}
I'd be happy to answer any clarification questions if needed. Thank you for the assistance.
without try-resource, you need close in final clause to make sure no leak. Or use Stream.flush() if you need more 'in-time' update.
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
outputStream.close();
}
You need to call flush() on the stream to write the bytes to the stream.
You're currently calling write() by itself, like this:
FileOutputStream outputStream = new FileOutputStream(fileLoc);
outputStream.write(content.getBytes());
What you want to do is this:
FileOutputStream outputStream = new FileOutputStream(fileLoc);
outputStream.write(content.getBytes());
outputStream.flush();
From the Javadoc (https://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html#flush--) for OutputStream (where FileOutputStream is an OutputStream), this is what it says for flush():
Flushes this output stream and forces any buffered output bytes to be written out. The general contract of flush is that calling it is an indication that, if any bytes previously written have been buffered by the implementation of the output stream, such bytes should immediately be written to their intended destination.
Even better would be to close the stream in a finally block, so that no matter what your code always tries to free up any open resources, like this:
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(fileLoc);
outputStream.write(content.getBytes());
outputStream.flush();
} finally {
if (outputStream != null) {
outputStream.close();
}
}
or use automatic resource management, like this:
try (FileOutputStream outputStream = new FileOutputStream(fileLoc)) {
outputStream.write(content.getBytes());
outputStream.flush();
}

Two outputstreams?

I have the following code where I'm trying to create two different types of outputstreams. This doesn't seem to work. What would be the correct way to create two outputstreams? Specifically, one dataoutputstream and one objectoutputstream?
connect();
try (DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream())) {
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream)) {
outputStream.writeUTF("saveFile");
outputStream.writeUTF(serverName);
File fileToSave = new File(localName);
byte[] fileContent = Files.readAllBytes(fileToSave.toPath());
objectOutputStream.writeObject(fileContent);
return true;
}
} catch (IOException e) {
return false;
} finally {
disconnect();
}
After doing some debugging it seems just like the outputstream isn't working. If I only have one of the two, the two "writeUTF" statements will execute.
If I keep both of the outputstreams, the message never reaches the server.
The solution was to move the two "writeUTF" statements above the second try block.
connect();
try (DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream())) {
outputStream.writeUTF("saveFile");
outputStream.writeUTF(serverName);
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream)) {
File fileToSave = new File(localName);
byte[] fileContent = Files.readAllBytes(fileToSave.toPath());
objectOutputStream.writeObject(fileContent);
return true;
}
} catch (IOException e) {
return false;
} finally {
disconnect();
}
Now the code executes properly.
The problem with your code is that new ObjectOutputStream(...) writes a header to the stream, and evidently your reading code isn't symmetrical with this code, i.e. it does the readUTF() steps before constructing the ObjectInputStream, so the header isn't consumed yet, so the readUTF() steps see it, and barf.
The solution is that you don't need to do this at all. The DataOutputStream is completely pointless here. ObjectOutputStream has all the methods of DatataOutputStream, and more, and similarly for the input streams.
In general this kind of thing is not possible when one or more of the streams is buffered, as ObjectInputStream is.

What is the correct order to close input streams?

I am studying a Java code example about reading file using input stream. I observed that there are 3 input streams initialized in the order of fis, bis, and dis(typed FileInputStream, BufferedInputStream, and DataInputStream correspondingly), with dependency fis<--(depends-on)--bis<--(depends-on)--dis. I also observed that they are closed in the same order: fis, bis, then dis.
My question is: shouldn't them be closed in REVERSE order? i.e. the latestly initialized shall be closed first?
Here is the code example. I also pasted it here:
public class BufferedInputStreamExample {
public static void main(String[] args) {
File file = new File("C:\\testing.txt");
FileInputStream fis = null;
BufferedInputStream bis = null;
DataInputStream dis = null;
try {
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
dis = new DataInputStream(bis);
while (dis.available() != 0) {
System.out.println(dis.readLine());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fis.close();
bis.close();
dis.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
The normal thing to do is to only close the outermost stream. DataInputStream and BufferedInputStream are both types of FilterInputStream, whose close method specifies that it calls the close method of the underlying stream. So you do not need to explicitly close the others or even maintain a reference to them in a variable. For example it is fine to initialize dis as:
dis = new DataInputStream(
new BufferedInputStream(
new FileInputStream(file)));
In practice, assuming the classes are implemented properly according to the spec, it does not matter whether you close any 1, any 2, or all 3 of the streams, in any order, or any number of times, because:
As said, closing an outer stream closes the inner stream.
Closing an already closed stream harmlessly does nothing. (InputStream and OutputStream implement the Closeable interface, whose close method states "If the stream is already closed then invoking this method has no effect.")
Only the FileInputStream actually needs to be closed, since it is the only one which holds open a real filesystem resource and therefore is the only stream which has visible side effects if held open (e.g., you cannot delete the file). The BufferedInputStream and DataInputStream are ordinary objects, which can be garbage collected in the ordinary way, whether closed or not. The FileInputStream will also be closed when garbage collected if you forgot to do it, but it's prudent to do it as soon as possible, since there are no guarantees about when garbage collection occurs.
So the example you posted is over-engineered, but not dangerous.
In modern Java (7+) the far more elegant way to ensure the closure of everything in your example, rather than using a finally block, is to use the try-with-resources statement, which lets you declare the streams, open them, and guarantee their closure, in one go:
try (DataInputStream dis = new DataInputStream(
new BufferedInputStream(
new FileInputStream(file)))) {
while (dis.available() != 0) {
System.out.println(dis.readLine());
}
} catch (IOException e) {
e.printStackTrace();
}
you only need to close the outer object (DataInputStream). it will close all the objects it depends on.
You could use try-with-resources and not worry about the order of closing
public class BufferedInputStreamExample {
public static void main(String[] args) {
File file = new File("C:\\testing.txt");
try(FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis)) {
while (dis.available() != 0) {
System.out.println(dis.readLine());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
I would suggest in the reverse of the order they are opened (so dis, bis then fis), but such isn't required (just style) or better yet - try-with-resources like
File file = new File("C:\\testing.txt");
try (FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis)) {
while (dis.available() != 0) {
System.out.println(dis.readLine());
}
} catch (IOException e) {
e.printStackTrace();
}
While the docs are not 100% clear, it looks like closing the DataInputStream should be sufficient.
Both DataInputStream and BufferedInputStream are subclasses of FilterInputStream, and here is its documentation of close() (Java 7 SE):
Closes this input stream and releases any system resources associated with the stream. This method simply performs in.close().
Here in is the wrapped stream.
Assuming neither class overrides the behaviour of the superclass, closing the DataInputStream will recursively close all the wrapped streams.

Initializing In Try/Catch

I have run into quite a snag while writing my app. Here is my issue:
I am trying to initialize the file input stream like so:
FileInputStream fis
fis = openFileInput(selectedFile);
Then put this 1 line later:
byte[] input = new byte[fis.available()];
Problem is both bits of code need try/catch statements and the second block cannot recognize fis because it was initialized within a try/catch. Here is my code:
private void openFile(String selectedFile) {
String value = "";
FileInputStream fis;
try {
fis = openFileInput(selectedFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
byte[] input = new byte[fis.available()];
} catch (IOException e) {
e.printStackTrace();
}
What should I do? (Thanks in advance)
The best approach in this situation is not to catch IOException at all.
private void openFile(String selectedFile) throws IOException {
FileInputStream fis = openFileInput(selectedFile);
byte[] input = new byte[fis.available()];
It does not make sense to continue after you got FileNotFoundException
Set FileInputStream fis = null; when you first declare the variable.
You could also run your code like this because IOException will also catch the file not found exception.
String value = "";
FileInputStream fis;
try {
fis = openFileInput(selectedFile);
byte[] input = new byte[fis.available()];
} catch (IOException e) {
e.printStackTrace();
}
Set the FileInputStream to a temporary value. null would be the best option, as in:
FileInputStream fis = null;
The reason for this is because if your try statement throws an error, then the fis will never me initialized. Then you'll have problems. If you don't exit the thing entirely, you should also add the statement after the try/catch blocks that tests if the value is null, just so that the program does not throw a null pointer exception.
So maybe something like:
if(fis == null) {
return; // Which will just end the method.
}
Also might want to put the try/catches together (you should still declare the other stuff outside of the try, at least anything you plan on using directly later on in the code) but it just might be more efficient coding wise), as in:
FileInputStream fis = null;
byte[] input = null;
try {
fis = openFileInput(selectedFile);
input = new byte[fis.available()];
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

java I/O, writng a array to a text file

i am using the following code to write an array to the file:
FileWriter fstream1=new FileWriter("outx.txt");
BufferedWriter out1= new BufferedWriter(fstream1);
FileWriter fstream2=new FileWriter("outy.txt");
BufferedWriter out2= new BufferedWriter(fstream2);
for(int i=0;i<320*240;i++)
{
out1.write(0+System.getProperty("line.separator"));//
// out1.write("\n");
out2.write(0+System.getProperty("line.separator"));
//out2.write("\n");
}
: here in the above code i am putting all zeros
the file should be containing 76800 lines( 0s) but my file is having only 69932 lines.
what is the problem and if you can suggest some other way to do this.
Did you remember to close the output streams? Your example doesn't list the calls to close(), which should flush the streams as well. BufferedWriter's default behavior is to flush (write) its remaining contents before closing the stream it is buffering.
You should probably add:
out1.close();
out2.close();
It is a very common case when the end of a file is being cut off that you forgot to close the writer used to create the file, especially when you have used a BufferedOutputStream or BufferedWriter that may not flush its buffer (write it to the file) until it has been explicitly flushed (or more commonly, closed).
It is a very good habit to get into to immediately write the close() call after opening the stream, and then write all of your code for working with the stream between the calls. Taking exceptions into account, the standard calls use the following idiom:
Writer myOutWriter = null;
try {
myOutWriter = new BufferedWriter(new FileWriter("..."));
// Write to myOutWriter here
} catch (IOException ioe) {
// Handle any exceptions here
} finally {
try {
if (myOutWriter != null) {
myOutWriter.close();
}
} catch (IOException ioe) {
// Not much you can do here
}
}
The Apache Commons IO Project (http://commons.apache.org/io/) has a nice utility called IOUtils.closeQuietly() that cleans up the finally block by including the try catch, null check, and call to close into one method call. An example using that library would look like this:
Writer myOutWriter = null;
try {
myOutWriter = new BufferedWriter(new FileWriter("..."));
// Write to myOutWriter here
} catch (IOException ioe) {
// Handle any exceptions here
} finally {
IOUtils.closeQuietly(myOutWriter);
}
Add:
out1.flush();
out2.flush();
After the for loop.
It is likely that your program is exiting before the buffers in the BufferedReader have been flushed, a common problem with working with buffered output.
Edit: The more correct solution would be:
public static void main(String[] args) throws IOException {
final String outputString = "0" + System.getProperty("line.separator");
BufferedWriter out1 = null;
BufferedWriter out2 = null;
try {
out1 = new BufferedWriter(new FileWriter("outx.txt"));
out2 = new BufferedWriter(new FileWriter("outy.txt"));
for(int i = 0; i < 320 * 240; i++) {
out1.write(outputString);
out2.write(outputString);
}
out1.flush(); // Not really needed as close will flush, but it is
out2.flush(); // useful for describing the intent of the code
} finally {
closeQuietly(out1);
closeQuietly(out2);
}
}
private static void closeQuietly(Closeable c) {
try {
if (c != null) {
c.close();
}
} catch (Exception e) {
// No-op
}
}
As others have pointed out, it is likely that there is unflushed data in your buffers.
An acceptable way to rewrite your code would be like this:
Writer out1 = new FileWriter("outx.txt");
try {
out1 = new BufferedWriter(out1);
Writer out2 = new FileWriter("outy.txt");
try {
out2 = new BufferedWriter(out2);
for (int i = 0; i < 320 * 240; i++) {
out1.write(0 + System.getProperty("line.separator"));
out2.write(0 + System.getProperty("line.separator"));
}
} finally {
out2.close();
}
} finally {
out1.close();
}
This code:
will flush data via close
will always release file handles via close, even if an error occurs (by using finally)
obeys the contract for the Closeable classes
doesn't muck around with null or swallow exceptions

Categories

Resources