This question already has answers here:
Why does a Try/Catch block create new variable scope?
(5 answers)
Closed 8 years ago.
I have the following code, which works nicely in my class reading a file line by line.
try { FileInputStream in = new FileInputStream(filename);
BufferedReader reader=new BufferedReader(new InputStreamReader(in));
String line;
while((line=reader.readLine())!=null){
// read the file
}
}
catch (Exception e) {
System.out.println(e);
}
But if I try to add the command close, for after the file was finished reading, then I got the error:
in.close();
Error:(131, 9) java: cannot find symbol
symbol: variable in
location: class ReadFile
I searched about cleaning objects after use and the need to close files before your program ends. And found several posts on this for Java, but many are very contradictory. The point is that in the end I just get very confused.
Am I wrong, or Java programming is a little bit fuzzy and messy? I mean, there is apparently no real use of destructor, the use of finalize is very questionable, and the use of close is also suggested as unnecessary. Some of the posts on these issues are contradictory and non-conclusive.
So, how to proceed here? In the case I really need to close the file, how to get rid of this error message? Is it really dispensable and unnecessary to close files? What about cleaning up class instances for the the program finishes?
You are getting the error because you have defined variable in inside the try block, so it is not visible in catch/finally/or anywhere outside that try. Move the declaration outside try:
Change this
try { FileInputStream in = new FileInputStream(filename);
to
FileInputStream in = null;
try { in = new FileInputStream(filename);
you may be closing in.close() out side try block so obviously you will get error because in is defined in try block which is local.
Better to use try with resource so you need not to manually close file stream
Ideally you must call the close() method inside the finally block, after the null check.
And for that you need to declare the variable in outside the try block.
Calling the close() method in finally block ensures that it is called irrespective of whether an Exception is thrown or not by the code in try block.
EDIT : This is when you are using Java 6 or earlier version. For Java 7 and higher you could use try with resource as suggested by #JqueryLearner
Related
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.
I'm using Java SDK8 and I created an inputStream and outputStream objects.
Prior to Java SE 7, I could use a finally block to ensure that these resources are closed regardless of whether the try statement completes normally or not.
I read that in Java SE 7 and later I can use a try-with-resources statement and in case the resource I'm using implements the interface java.lang.AutoCloseable I don't need to close this resource in the finally block any more.
My questions are:
1. Is it correct that if I'm using a resource that implements the interface java.lang.AutoCloseable I don't need to close it in the finally block and it will be closed even if an exception will be thrown? if so, Is there a precondition that must exist? (e.g. creating the resource inside a try block?)
2. What does the try-with-resources statement exactly mean?
Thanks a lot in advance!!
Is it correct that if I'm using a resource that implements the interface java.lang.AutoCloseable I don't need to close it in the finally block and it will be closed even if an exception will be thrown?
Yes.
if so, Is there a precondition that must exist? (e.g. creating the resource inside a try block?)
The resource must be created within the try-with-resources statement (see below).
What does the try-with-resources statement exactly mean?
Here's a try-with-resources statement:
try (FileReader fr = FileReader(path)) {
// use fr here
}
Note how the initialization of the FileReader is in the try (in the new () part). That's how the statement knows what needs to be closed later.
(More in the tutorial, though I don't like their first example because it relies on A) The fact that the BufferedReader constructor never throws, and B) The fact that BufferedReader will close the FileReader when the BufferedReader is closed. Those are true for BufferedReader, but it's a poor example in the general case.)
The full gritty details, including a translation of what a try-with-resources looks like in the old try/catch/finally format, are in the specification.
Note that you can create multiple resources in the statement; they're closed in reverse order of creation:
try (
FileReader fr =
new FileReader(fileName);
NiftyThingUsingReader nifty =
new NiftyThingUsingReader(fr)
) {
// ...use `nifty` here
}
Although you could write:
try (
NiftyThingUsingReader nifty =
new NiftyThingUsingReader(new FileReader(fileName))
) {
// ...use `nifty` here
}
...you'd have to know for sure that NiftyThingUsingReader(FileReader) never throws an exception, and that NiftyThingUsingReader#close will close the underlying FileReader, because it will not be handled by the try-with-resources itself. If you're unsure, keep them separate, so that the try-with-resources statement closes the FileReader even if the NiftyThingUsingReader(FileReader) constructor throws, and even if NiftyThingUsingReader#close doesn't close it.
The resources don't have to be relying on each other (directly); for instance, this is a fairly common situation where you want both the input and output to be handled:
try (
java.util.zip.ZipFile zf =
new java.util.zip.ZipFile(zipFileName);
java.io.BufferedWriter writer =
java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
) {
// Enumerate each entry
for (java.util.Enumeration entries =
zf.entries(); entries.hasMoreElements();) {
// Get the entry name and write it to the output file
String newLine = System.getProperty("line.separator");
String zipEntryName =
((java.util.zip.ZipEntry)entries.nextElement()).getName() +
newLine;
writer.write(zipEntryName, 0, zipEntryName.length());
}
}
I am trying to figure out how to make sure a temporary file that gets created in a method gets deleted by the time the method returns. I have tried file.deleteOnExit();, but that is for when the program stops, not the method. I have also tried a try and finally block. Is using a finally block the only way to achieve this?
public String example(File file) {
// do some random processing to the file here
file.canWrite();
InputStream() is = new FileInputStread(file);
// when we are ready to return, use the try finally block
try {
return file.getName();
} finally {
is.close();
file.delete();
}
}
I think it looks ugly. Anyone have a suggestion?
As it was mentioned by #BackSlash in your specific case you can just remove file just before return:
file.delete();
return "File processed!";
However in common case if code inside try block can throw exception your approach looks fine. You can also use Aspect Oriented Programming (e.g. using AspectJ) but it looks like overkill in your case.
You can also improve your code by using nice new feature of Java 7. Each instance of Closable will be closed in the end of try block, e.g.:
try (
InputStream in = ...
) {
// read from input stream.
}
// that's it. You do not have to close in. It will be closed automatically since InputStream implements Closable.
So, you can create class AutoDeletableFile that wraps File and implements Closable. The close() method should delete the file. In this code will work exactly as yours:
try (
AutoDeletableFile file = new AutoDeletableFile("myfile.txt");
) {
// deal with file
}
// do nothing here. The file will be deleted automatically since its close() method actually deletes the file.
Well, that's what finally is for.
Of course, in Java7 you can write an AutoCloseable implementation that does the deleting for you and use try-with-resources instead.
If you are using Java 7 you can achieve this by using java.lang.AutoCloseable interface. Details here http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html.
If not then finally is the best and widely used approach for closing/cleaning resources.
Maybe try delete the file at the end of the method (the last line)? This will delete the file right before the method exits if I understand correctly?
File file = new File("file.txt");
file.delete();
i was doing a sample about reading files. I put a txt file into project folder and wrote this code but I got the exception FileNotFound and also when I try to close dataInputStream I am getting compile error(commented out line). I think I messed up everything
String str=null;
try {
FileInputStream fileInputStream=new FileInputStream("myfile.txt");
DataInputStream dataInputStream=new DataInputStream(fileInputStream);
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(dataInputStream));
str=bufferedReader.readLine();
} catch (Exception e) {
System.out.println(e.getMessage());
}
System.out.println(str);
//dataInputStream.close();
Java is really nitpicky about relative paths, so `"myfile.txt" should probably live wherever your project is being built.
As for closing the dataInputStream, it is not in scope. Declare it outside of your try block. In any case, I'd suggest placing the actual close() call in a finally block to make sure it is always done (if the reference isn't null).
I agree with Guillermo
myfile.txt needs to be in your class path.
If you run this code in command line, it should be located in the same folder as this code executes, or same package.
as for the datainput stream it is out of scope
bufferedReader.close() must use in the end of where you close this operation..
i noticed in a java program the below line used to open a file and process it
BufferedReader inp = new BufferedReader(new FileReader(inputFile));
In the javaprogram the inp is not closed before exiting the program the below line is missing
if (inp != null)
try {
inp.close();
} catch (IOException logOrIgnore) {}
The program has exits in a lot of place but they had not closed the file. Do i need to put this line everywhere? If i dont close the file when the program exits will it be a issue.
Does the garbage collector closes the file?
You should use try/finally:
Reader inp = new BufferedReader(new FileReader(inputFile));
try {
// Do stuff with "inp"
} finally {
IOUtils.closeQuietly(inp);
}
IOUtils is from Apache Commons IO. Its closeQuietly method is like your code snippet above: it calls close, and ignores any exceptions thrown.
The garbage collector does not close the file. If you know your program will not be long running or open many files, you can get away without closing the file. But otherwise you need to close it manually.
It sounds like you're using the BufferedReader without returning to the context in which it was declared (possibly an instance variable?). In that instance, you must close it manually upon each possible exit from your application. You cannot rely on the garbage collector to do this for you.