Closing a FileOutputStream in java without a reference to it? - java

In java, we can do the following:
new FileOutputStream(new File("dir"));
(Excluding the exception handling for talks sake).
Should we somehow close the stream in this instance? if so how do we do it? if we don't create a local reference within a method for example:
FileOutputStream fos = new FileOutputStream(new File("dir"));
Is it bad practice to handle a stream shown in the first example? does java handle / close itself in that instance?
I receive some poor static code analysis when using the
foo = new FileOutputStream(new File("dir"));
because the stream is not closed, but I can't get a handle to close it? or maybe I can and i'm just not aware how.
Thank you all for the feedback, my apologies on not making my example relevant and clear. please see my actual code below:
public void generateEnvironmentProperties() {
Properties props = new Properties();
properties.getAllProperties().forEach((k,v) -> props.setProperty(k,v));
try {
File f = new File("target\\allure-results\\environment.properties");
if (!f.getParentFile().mkdirs()) {
throw new IOException("Unable to create file(s)");
}
if (!f.createNewFile()) {
throw new IOException("Unable to create file(s)");
}
props.store(new FileOutputStream(f), "Allure Environment Properties");
} catch(IOException ioe) {
LOG.fatal(ioe);
}
}

As the Properties.store javadoc says:
After the entries have been written, the output stream is flushed.
The output stream remains open after this method returns.
So it is indeed required that you hold on to the instance of FileOutputStream you're using and close it yourself.

you can use try-with-resources, one of the Java 7 feature
try(FileOutputStream fos = new FileOutputStream(f)){
// use resources, for example:
props.store(fos , "Allure Environment Properties");
} catch (FileNotFoundException e) {
// exception handling, for example:
LOG.fatal(ioe);
}
the resources are closed as soon as the try-catch block is executed

props.store(new FileOutputStream(f), "Allure Environment Properties");
DON'T DO THIS. As your IDE warns you, the output stream will not be closed. You have two options:
Keep a reference to the stream and close it yourself. You will need to write the correct try...catch...finally statement to make sure the stream is closed even if an exception is thrown.
If you are using Java 7 or later, use try with resources. This new form of the try...catch statement will automatically close a stream when the try block exists.

Related

Issues with multiple FileOutputStreams to the same file in Java

I'm trying to write to a file using FileOutputStream. When the user selects what file to write to, the program tries to create a FileOutputStream using that file, to check if it works. If it does not, the user has to select a different file. If it does work, the FileOutputStream is closed.
After a file, for which a FOS can be opened, has been selected the program tries again to create another FOS, but this sometimes fails.
I know that you cannot write to a file when it is open on your computer. Could it be that the first FOS has not been "fully closed" and therefore the file is still considered open, so that the second FOS can not write to it?
In the following code, what happens is that the first creation and closing of the FOS does not throw an exception, while the second one somehow does. How can this be?
(I know the problem can be solved by simply using the first FOS and not creating a second, but I am interested in understanding why this particular code behaves the way it does.)
try {
FileOutputStream out1 = new FileOutputStream(file);
out1.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
FileOutputStream out2 = new FileOutputStream(file);
} catch (Exception e) {
e.printStackTrace();
}
Based on the symptoms, I surmise that you are using Windows, and the error you are getting in the second open is "file is in use".
Apparently under some circumstances, Windows does not immediately close a file when the application (in this case the JVM) closes the FileHandle:
FileStream.Close() is not closing the file handle instantly
Delay between CloseHandle function call and SMB Close request
This is not Java's doing, and I am not aware of a workaround (in Java) apart from waiting a bit and retrying.
(You could see what happens if you add a Thread.sleep(1000); before the 2nd attempt to create a FileOutputStream.)

Looking for an explanation regarding file.delete() method in try catch block

Trying to make a simple 'cut' program to move files across folders.
After it makes a copy it should delete the source file but it ignores the fileLocation.delete(); method in the try block. If I put it in the 'finally' block it works and also anywhere else in the program after it goes through copying the file but that makes no sense for it to work that way, even if something goes wrong the source will be deleted. My question is why does it ignore it, I was unable to find answers online. Thank you.
File fileLocation = new File("C:\\fileLocation\\picture.png");
File fileDestination = new File("C:\\fileDestination\\picture.png");
try(FileInputStream input = new FileInputStream(fileLocation);
FileOutputStream output = new FileOutputStream(fileDestination)) {
byte[] buffer = new byte[1024];
int length;
while((length = input.read(buffer)) > 0) {
output.write(buffer,0, length);
}
fileLocation.delete();
} catch(IOException exc) {
System.out.println(exc.getMessage());
}
try(FileInputStream input = new FileInputStream(fileLocation);
... ) {
// ..
fileLocation.delete();
}
At this point, input is still open, so you can't delete the file it refers to.
According to the definition of try-with-resources in the language spec, a finally block on a try-with-resources statement will be executed after the resource is closed. As such, putting the delete in the finally block means it can succeed.
Rather than putting it in the finally (which occurs whether or not an exception is thrown), you can split up the resources into two try-with-resources blocks, and delete once you're done with input:
try (FileOutputStream output = ...) {
try (FileInputStream input = new FileInputStream(fileLocation)) {
// ..
}
// input is now closed.
fileLocation.delete();
} catch(IOException exc) {
System.out.println(exc.getMessage());
}
Now, fileLocation is only deleted when no IOException is thrown from any preceding statement in the output try-with-resources block (including the input try-with-resources block).
Or, if you want not to delete it until output is closed: move the IOException catch into a surrounding try/catch (not try-with-resources) block:
try {
try (FileOutputStream output = ...;
FileInputStream input = ...) {
// ..
}
// input and output are now both closed.
fileLocation.delete();
} catch(IOException exc) {
System.out.println(exc.getMessage());
}
Of course, a better way to move a file would be to use the utility method to move files, e.g.
Files.move(fileLocation.toPath(), fileDestination.toPath(), CopyOption.REPLACE_EXISTING);
You're using the wrong API. File.delete() is known-bad API design.
This is what's bad about it, and why it explains your confusion: Unlike just about any other API, if delete() fails to delete, it does not throw any exceptions. Instead, it returns false. This is bad in 3 important ways:
It's un-java-like. Very few APIs do that; the vast majority of them throw something instead.
It is easy to 'forget'. Just writing x.foo(); on its own, where foo() is any method that returns something (i.e. has a non-void return type), is perfectly fine java. it's java-ese for: Run this method, then take the result and toss it in the garbage. You've done that here: Call delete() and ignore the result. For delete(), that's not actually okay unless you intended to write code that effectively means: "try to delete this path. Whether it succeeds or not, continue with the code". Which, usually, isn't what you want.
If something does go wrong, it is not possible for the delete() method to tell you any details other than 'I could not accomplish it'. No way to have a message or some sort of exception type to clear things up for you.
The solution is simple. Stop using this method. Put it on the banlist: This method should no longer ever be invoked in java code. If you are maintaining some 15 year old stuff, it's fine, I guess, but a quick refactor to get rid of it wouldn't go amiss.
Great! So what's the new one I should be using?
The path/files API in the java.nio.file package.
Replace:
File f = new File("a/b/c.txt");
f.delete();
with:
Path p = Paths.get("a/b/c.txt");
Files.delete(p);
Unlike file.delete(), Files.delete(path) WILL throw an exception if the deletion cannot be performed. This exception then contains suitable information about why. For example, because the file doesn't exist, or because you do not have write access to the underlying directory, or because the file system is mounted read only, etcetera.
The new File API is also vastly more capable. It can properly handle links or alternate file systems, for example. It also has more methods. For example, it has the Files.move method which may be of particular use here.
Just for reference, why is my delete operation failing?
Probably because your own process still has the file open. On some OS/filesystem combos (in particular, on windows and e.g. NTFS), you can't delete open files. Even if your own process is the one that still has the file open.
If you use Files.delete() you'll get an exception with a message that'll get you a lot closer to that conclusion than 'the delete() call returned false', fortunately.

Rollback or Reset a BufferedWriter

A logic that handles the rollback of a write to a file is this possible?
From my understanding a BufferWriter only writes when a .close() or .flush() is invoked.
I would like to know is it possible to, rollback a write or undo any changes to a file when an error has occurred?
This means that the BufferWriter acts as a temporary storage to store the changes done to a file.
How big is what you're writing? If it isn't too big, then you could write to a ByteArrayOutputStream so you're writing in memory and not affecting the final file you want to write to. Only once you've written everything to memory and have done whatever you want to do to verify that everything is OK can you write to the output file. You can pretty much be guaranteed that if the file gets written to at all, it will get written to in its entirety (unless you run out of disk space.). Here's an example:
import java.io.*;
class Solution {
public static void main(String[] args) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
// Do whatever writing you want to do here. If this fails, you were only writing to memory and so
// haven't affected the disk in any way.
os.write("abcdefg\n".getBytes());
// Possibly check here to make sure everything went OK
// All is well, so write the output file. This should never fail unless you're out of disk space
// or you don't have permission to write to the specified location.
try (OutputStream os2 = new FileOutputStream("/tmp/blah")) {
os2.write(os.toByteArray());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
If you have to (or just want to) use Writers instead of OutputStreams, here's the equivalent example:
Writer writer = new StringWriter();
try {
// again, this represents the writing process that you worry might fail...
writer.write("abcdefg\n");
try (Writer os2 = new FileWriter("/tmp/blah2")) {
os2.write(writer.toString());
}
} catch (IOException e) {
e.printStackTrace();
}
It is impossible to rollback or undo changes already applied to files/streams,
but there are tons of alternatives to do so:
One simple trick is to clean the destination and redo the process again, to clean the file:
PrintWriter writer = new PrintWriter(FILE_PATH);
writer.print("");
// other operations
writer.close();
You can remove the content entirely and re-run again.
Or if you are sure the last line(s) are the problems, you may do remove last line actions for your purpose, such as rollback the line instead:
Delete last line in text file

java exception handling in constructor

honestly I'm not very experienced with exception handling, because often for my laziness I tend to not handle exceptions. So here's a very basic question.
I would like to know what's the cleanest way to accomplish this situation, with an exception handling approach:
I have a class (ConfigManager) that reads a file within its constructor, and need that file to exists to be constructed correctly, given as the constructor parameter.
If the file doesn't exist, I would like to catch the FileNotFoundException, create the file with some defaults values, and continue the creation of the ConfigManager object with the default config file now available.
Here's some code:
class ConfigManager{
ConfigManager(String file){
try{
builder = builderFactory.newDocumentBuilder();
document = builder.parse (new FileInputStream(file));
....
}catch (FileNotFoundException e) {
File configFile = new File (file);
try {
configFile.createNewFile();
BufferedWriter writer = new BufferedWriter(new FileWriter(configFile));
writer.write(this.defaultConfig);
writer.close();
return new ConfigManager(string); //Here's the problem. I can't do that but I need to try build ConfigManager again. How do that?
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
How to construct a new ConfigManager object, after the default config file has been created?
Is that the rigth way to handle such type of exception?
thanks in advance
What you can do is ensure the file exists before attempting to parse it.
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
} catch (FileNotFoundException e) {
BufferedWriter writer = new BufferedWriter(new FileWriter(configFile));
writer.write(defaultConfig);
writer.close();
fis = new FileInputStream(file);
}
try{
builder = builderFactory.newDocumentBuilder();
document = builder.parse (fis);
don't do the reading file in the constructor, create a method (possibly private) that does the reading of the file and setting of the values on the ConfigManager.
Then in the constructor, where you try to call the constructor again, just call the method.
i.e. dont call the constructor again.
update -- I would organize the code like this:
ConfigManager(String fileName) {
File file = new File(fileName);
if (!file.exists()){
// create this method -- Im assuming its ok to put the default
// config on the path where the file did not exist.
createDefaultConfigFile(fileName);
}
parseConfigFile(fileName, ...); // create this method too
}
this is obviously not working code, and I dont know specifically what you are doing so its as far as I can go. But its more readable than what you have now, and a bit more organized. Also, do you really want to create a new default config file if the specified one does not exist? Why not pop up a warning saying the config did not exist so you are using defaults, but not write the default file? You might have a reason to write the default, and if thats true then ok, but if you don't have to, don't add more work...
The solution is to partition your constructor into two parts. The first part tries to create the FileInputStream from the existing file. If it throws the FileNotFoundException, then you create and populate the file as above, and then open the FileInputStream again. The second part takes the file FileInputStream opened by the first part (regardless of how it was opened) and proceeds with initialization.
Another option is to defer this loading to an init() method, so that consumers of your class must both create and initialize their objects.
You need to be able to call the constructor again, but without creating a new object - just calling it on the same object. Since Java doesn't allow you to do that, you have to create an auxillary method, move the code from the constructor into that, and then call the new method from the constructor.
This is a basic technique for any situation where you need to implement recursion, but you can't directly recurse.
The cleanest way of accomplishing this is not to perform any operations that can result in exceptions in the constructor. If you absolutely need to perform them before your object can be used, do them in a separate method init().
Try delegating the parsing of the configuration file to another method. That way, you can check if the file exists first and then either create a default one, or pass the existing one to this new method.
Well, actually you have a new instance of ConfigManager after the constructor was executed without an error. So all you have to to is to just remove the line in question.
Or consider using a static initializer. This will check for the file only once, when your application is deployed/started.
often for my laziness I tend to not
handle exceptions
I suggest you fix the laziness first. In reality you are just creating more work for yourself further down the line.

Closing Java InputStreams

I have some questions about the usage of the close() method when using Java InputStreams. From what I see and read from most developers, you should always explicitly call close() on an InputStream when it is no longer needed. But, today I was looking into using a Java properties file, and every example I have found has something like this:
Properties props = new Properties();
try {
props.load(new FileInputStream("message.properties"));
//omitted.
} catch (Exception ex) {}
With the above example, there is no way to explicitly call close() because the InputStream is unreachable after it is used. I have seen many similar uses of InputStreams even though it seems to contradict what most people say about explicitly closing. I read through Oracle's JavaDocs and it does not mention if the Properties.load() method closes the InputStream. I am wondering if this is generally acceptable or if it is preferred to do something more like the following:
Properties props = new Properties();
InputStream fis = new FileInputStream("message.properties");
try {
props.load(fis);
//omitted.
} catch (Exception ex) {
//omitted.
} finally {
try {
fis.close();
} catch (IOException ioex) {
//omitted.
}
}
Which way is better and/or more efficient? Or does it really matter?
The Properties class wraps the input stream in a LineReader to read the properties file. Since you provide the input stream, it's your responsibility to close it.
The second example is a better way to handle the stream by far, don't rely on somebody else to close it for you.
One improvement you could make is to use IOUtils.closeQuietly()
to close the stream, e.g.:
Properties props = new Properties();
InputStream fis = new FileInputStream("message.properties");
try {
props.load(fis);
//omitted.
} catch (Exception ex) {
//omitted.
} finally {
IOUtils.closeQuietly(fis);
}
I would go with a try-with-resources (at least for Java 7+):
Properties props = new Properties();
try(InputStream fis = new FileInputStream("message.properties")) {
props.load(fis);
//omitted.
} catch (Exception ex) {
//omitted.
}
The close() call should be automatically called when the try block is exited.
The examples in the Properties Tutorial close the FileInputStream explicitly after loading, so I think it's safe to assume that the load method isn't responsible for it, you are.
// create and load default properties
Properties defaultProps = new Properties();
FileInputStream in = new FileInputStream("defaultProperties");
defaultProps.load(in);
in.close();
Just for reference, I checked the Apache Harmony implementation of Properties, and it does not close the stream on load.
If you're using Java 7+ you can use this:
try(InputStream is = new FileInputStream("message.properties")) {
// ...
}
It doesn't mention in the documentation that props.load would close the input stream. You should close the input stream manually in a finally block like you suggest.
It isn't normal for a function to close an InputStream. The same convention applies as with memory in non-garbage-collected languages: If possible, the one who opens the stream should close the stream. Otherwise, it's very easy to leave a stream open (you think a function's going to close it, but it doesn't, or something...)
It looks like the first code sample ends up relying on the finalize method in FileInputStream to actually close the file. I would say your second example is better, even though in both cases the file does get closed.
There are cases like the Byte streams where close does nothing and can be omitted, otherwise I think it's better to explicitly close the file in a finally block. If you open it, you close it.
There is a book on Oracle's site called Java Platform Performance that discusses finalizers in its appendix, it says:
You are almost always better off doing your own cleanup instead of relying on a finalizer. Using a finalizer can also leave behind critical resources that won't be recovered for an indeterminate amount of time. If you are considering using a finalizer to ensure that important resources are freed in a timely manner, you might want to reconsider.
Let me add a little something to other people's answers.
If you can import Apache Commons IO, you could make use of the ever-so-handy AutoCloseInputStreams classes: you wrap your InputStream and then you just use your wrapped instance and it gets automatically closed as soon as the end of input has been reached or when the stream is explicitly closed, whichever comes first.
Because FileInputStream implements finalize() and invoke close() in `finalize.
So when not so frequently used, there is no need to close FileInputStream

Categories

Resources