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();
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 need to write a custom batch File renamer. I've got the bulk of it done except I can't figure out how to check if a file is already open. I'm just using the java.io.File package and there is a canWrite() method but that doesn't seem to test if the file is in use by another program. Any ideas on how I can make this work?
Using the Apache Commons IO library...
boolean isFileUnlocked = false;
try {
org.apache.commons.io.FileUtils.touch(yourFile);
isFileUnlocked = true;
} catch (IOException e) {
isFileUnlocked = false;
}
if(isFileUnlocked){
// Do stuff you need to do with a file that is NOT locked.
} else {
// Do stuff you need to do with a file that IS locked
}
(The Q&A is about how to deal with Windows "open file" locks ... not how implement this kind of locking portably.)
This whole issue is fraught with portability issues and race conditions:
You could try to use FileLock, but it is not necessarily supported for your OS and/or filesystem.
It appears that on Windows you may be unable to use FileLock if another application has opened the file in a particular way.
Even if you did manage to use FileLock or something else, you've still got the problem that something may come in and open the file between you testing the file and doing the rename.
A simpler though non-portable solution is to just try the rename (or whatever it is you are trying to do) and diagnose the return value and / or any Java exceptions that arise due to opened files.
Notes:
If you use the Files API instead of the File API you will get more information in the event of a failure.
On systems (e.g. Linux) where you are allowed to rename a locked or open file, you won't get any failure result or exceptions. The operation will just succeed. However, on such systems you generally don't need to worry if a file is already open, since the OS doesn't lock files on open.
// TO CHECK WHETHER A FILE IS OPENED
// OR NOT (not for .txt files)
// the file we want to check
String fileName = "C:\\Text.xlsx";
File file = new File(fileName);
// try to rename the file with the same name
File sameFileName = new File(fileName);
if(file.renameTo(sameFileName)){
// if the file is renamed
System.out.println("file is closed");
}else{
// if the file didnt accept the renaming operation
System.out.println("file is opened");
}
On Windows I found the answer https://stackoverflow.com/a/13706972/3014879 using
fileIsLocked = !file.renameTo(file)
most useful, as it avoids false positives when processing write protected (or readonly) files.
org.apache.commons.io.FileUtils.touch(yourFile) doesn't check if your file is open or not. Instead, it changes the timestamp of the file to the current time.
I used IOException and it works just fine:
try
{
String filePath = "C:\sheet.xlsx";
FileWriter fw = new FileWriter(filePath );
}
catch (IOException e)
{
System.out.println("File is open");
}
I don't think you'll ever get a definitive solution for this, the operating system isn't necessarily going to tell you if the file is open or not.
You might get some mileage out of java.nio.channels.FileLock, although the javadoc is loaded with caveats.
Hi I really hope this helps.
I tried all the options before and none really work on Windows. The only think that helped me accomplish this was trying to move the file. Event to the same place under an ATOMIC_MOVE. If the file is being written by another program or Java thread, this definitely will produce an Exception.
try{
Files.move(Paths.get(currentFile.getPath()),
Paths.get(currentFile.getPath()), StandardCopyOption.ATOMIC_MOVE);
// DO YOUR STUFF HERE SINCE IT IS NOT BEING WRITTEN BY ANOTHER PROGRAM
} catch (Exception e){
// DO NOT WRITE THEN SINCE THE FILE IS BEING WRITTEN BY ANOTHER PROGRAM
}
If file is in use FileOutputStream fileOutputStream = new FileOutputStream(file); returns java.io.FileNotFoundException with 'The process cannot access the file because it is being used by another process' in the exception message.
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
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.
I'm writing string to temporary file (temp.txt) and I want that file should open after clicking button of my awt window it should delete when I close that file (after opening that file), how can I do this?
This is the code that I have been using to create temporary file in Java:
File temp = File.createTempFile("temp",".txt");
FileWriter fileoutput = new FileWriter(temp);
Bufferedwriter buffout = new BufferedWriter(fileoutput);
A file created by:
File temp = File.createTempFile("temp",".txt");
Will not be deleted, see javadoc, you have to call
temp.deleteOnExit();
so the JVM will delete the file on exit...
How about something like:
if (!temp.delete())
{
// wasn't deleted for some reason, delete on exit instead
temp.deleteOnExit();
}
Some links that might help you:
File.getAbsoluteFile()/getAbsolutePath().
FileReader.
File.delete().
To perform an operation when clicking a button, you will need code something like this:
button.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent event) {
fileOperation();
}
}
...
private void fileOperation() {
... do stuff with file ...
}
You can probably find many examples with google. Generally the anonymous inner class code should be short and just translate the event and context into operations meaningful to the outer class.
Currently you need to delete the file manually with File.delete after you have closed it. If you really wanted to you could extends, say, RandomAccessFile and override close to delete after the close. I believe delete-on-close was considered as a mode for opening file on JDK7 (no idea if it is in or not).
Just writing to a file, as in your code, would be pointless. You would presumably want to delete the file after closing a read stream no the write stream. It's not a bad idea to avoid temporary files if you possibly can.