Delete temp file during finally vs delete output file during catch - java

This is in Java 6.
I've seen more than once that people create temp files, do something, then rename it to the output file. Everything is wrapped in a try-finally block, where the temp file is deleted in finally in case something goes wrong in between.
try {
//do something with tempFile
//do something with tempFile
//do something with tempFile
tempFile.renameTo(outputFile);
}
finally {
if (tempFile.exists())
tempFile.delete()
}
I was wondering what are the benefits of doing that instead of doing something to the output file directly and delete it in case of exceptions.
try {
//do something with outputFile
//do something with outputFile
//do something with outputFile
}
catch (Exception e) {
if (outputFile.exists())
outputFile.delete();
}
My guess is that deleting temp files in finally benefits me when the try block can throw many kinds of exceptions. Is my guess right? What else?

finally is always executed while the catch above is not executed for exceptions that derive from java.lang.Error plus it will delete the file also when it can't be renamed (this operation doesn't throw an exception when it fails ... an ancient bug in Java IO).

Working with the temp file until the operation is complete will insure you are not ending up with an output file which is partly modified.
In addition the finally block will execute regardless of the outcome while the catch block will only take place when an exception surfaces.
A more in depth example would be...
try {
//do something with tempFile
//operation is complete since we made it this far; transition
//tempFile into outputFile
tempFile.renameTo(outputFile);
}
catch (Exception e) {
//perform error logic
}
finally {
if (tempFile.exists())
tempFile.delete()
}

finally always executes, so the difference is that in the first case that file is always deleted (for both normal execution and exception thrown). If you only want to delete that file if something went wrong, go with deleting in the catch block.

As far as I know delete/copy and other file operations are done via the OS API and there is no guaranty that those APIs work at the moment. for example if your own program and any other program keep the temp file open, the API won't be able to delete the file. So in the case of working with TEMP file if this happens user won't have the bad file, instead have a temp file and he/she has no idea about what the file is for, but if you work directly with the main file, in the case of any failure in deleting the file, your user will have a file which contains bad data, I think

Related

Java: deleting gz files failed occasionally

UPDATE 2: Please close this question
After further debugging it is found that the problem is not in the inner try block, but a bug inside the 'while' loop. An exception was caused there and was not caught, which therefore skips the inner try block. Apologies for my mistake, please delete this thread.
UPDATE: added logging to capture errors during delete.
I am downloading 8000ish GZ files from a server, process its content locally, then delete the downloaded copy upon completion. I am running this over a number of threads, each process a disjoint batch of GZ files. But I do not understand for what reason that my code does not successfully delete the GZ files occasionally (not always). The code generally looks like this:
....
private static final Logger LOG = Logger.getLogger(....class.getName());
.....
for (String inputGZFile : gzFiles) { //gzFiles is a list of urls to be process by this thread
try {
File downloadTo = new
File(this.outFolder + "/" + new File(downloadFrom.getPath()).getName());
FileUtils.copyURLToFile(downloadFrom, downloadTo);
InputStream fileStream = new FileInputStream(downloadTo);
InputStream gzipStream = new GZIPInputStream(fileStream);
Reader decoder = new InputStreamReader(gzipStream, Charset.forName("utf8"));
Scanner inputScanner = new Scanner(decoder);
inputScanner.useDelimiter(" .");
while (inputScanner.hasNextLine() && (content = inputScanner.nextLine()) != null) {
//do something
}
try {
inputScanner.close();
FileUtils.forceDelete(downloadTo);
}catch (Exception e){
LOG.info("\t thread " + id + " deleting gz file error "+ inputGZFile);
LOG.info("\t thread " + id+ExceptionUtils.getFullStackTrace(e));
}
}catch(Exception e){
e.printStackTrace();
}
}
The only reason I can think of is that the scanner did not close the file or release the file handle. But that would be strange because I already call the close method to close the scanner.
Any suggestions highly appreiciated.
Without the ability to look into your log files, or debug your system first hand, it is close to impossible to tell you what is going wrong here.
But what you can definitely do: do that call to FileUtils.forceDelete(downloadTo); within a finally block for example.
The whole point of try/catch/finally is to enable you to enforce that specific actions always take place, no matter what happened in the try block!
Also note: if you are unable to tell what your code does, then add logging support to it. So that instead of printStackTrace(); you log the whole exception to a place where it does not get lost.
Meaning: the real answer here is that you step back and take the necessary actions to find out where your problems are coming from.

AccessDeniedException when Creating a recently deleted file

I am trying to delete a file and then recreate it. First I check to see if the file already exists, then, if it does, I delete it. Then I try to create a new file in the same place with the same name. When I do this I get this error:
java.nio.file.AccessDeniedException: inputLog.txt
However, if the file did not exist before running these three operations, then the file is created without issue.
Here is my code:
final Path INPUTLOGPATH = FileSystems.getDefault().getPath("inputLog.txt");
try {
reader = Files.newBufferedReader(INPUTLOGPATH, charset);
} catch (IOException e) {
reader = null;
}
if (reader != null) {
try {
Files.delete(INPUTLOGPATH);
} catch (IOException e) {
e.printStackTrace();
}
}
try {
Files.createFile(INPUTLOGPATH);
} catch (IOException e) {
e.printStackTrace();
}
First I check to see if the file already exists, then, if it does, I delete it.
Why? Opening the file for output will already do all that. You're just repeating work that the operating system already has to do. Remove all this. You're doing it wrong by not closing the file reader, but it's irrelevant. Don't write unnecessary code.
Then I try to create a new file in the same place with the same name
That is also unnecessary as shown. Just open the file for output when you need it.
As you have it now:
you're opening the file, which is a search, among many other things
you're deleting the file, which is another search
you're creating the file, which is another search
then presumably you're opening the file for output, which requires another search, another deletion, and another creation, internally to the operating system.
Don't do this. Just remove all this code. It accomplishes exactly nothing.
You're also introducing all kinds of timing-window problems by this approach, and you still have to deal with eventual failure at the point where you actually open the file for output.

How to check that file is opened by another process in Java? [duplicate]

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.

Pause the execution of Java if files are used

My application writes to Excel files. Sometimes the file can be used, in that case the FileNotFoundException thrown and then I do not know how to handle it better.
I am telling the user that the file is used and after that message I do not want to close the application, but to stop and wait while the file is available (assuming that it is opened by the same user). But I do not understand how to implement it. file.canWrite() doesn't work, it returns true even when the file is opened, to use FileLock and check that the lock is available I need to open a stream, but it throws FileNotFoundException (I've been thinking about checking the lock in a busy wait, I know that it is not a good solution, but I can't find another one).
This is a part of my code if it can help somehow to understand my problem:
File file = new File(filename);
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
FileChannel channel = out.getChannel();
FileLock lock = channel.lock();
if (lock == null) {
new Message("lock not available");
// to stop the program here and wait when the file is available, then resume
}
// write here
lock.release();
}
catch (IOException e) {
new Message("Blocked");
// or to stop here and then create another stream when the file is available
}
What makes it more difficult for me is that it writes to different files, and if the first file is available, but the second is not, then it will update one file and then stop, and if I restart the program, it will update it again, so I can't allow the program to write into files until all of them are available.
I believe that there should be a common solution, since it must be a common issue in Windows to deal with such cases, but I can't find it.
To wait until a file exists you can make a simple loop:
File file = new File(filename);
while (!file.exists()) {
try {
Thread.sleep(100);
} catch (InterruptedException ie) { /* safe to ignore */ }
}
A better solution could be using WatchService but it's more code to implement.
The File.canWrite method only tells you if a path can be written to; if the path names a file that doesn't exist it will return false. You could use the canRead method instead of exists in a loop like above.
To use a file locks, the file has to exist first, so that wouldn't work either.
The only way to be sure you can write to a file is to try to open it. If the file doesn't exist, the java.io API will create it. To open a file for writing without creating you can use the java.nio.file.Files class:
try (OutputStream out = Files.newOutputStream(file.toPath(),
StandardOpenOption.WRITE))
{
// exists and is writable
} catch (IOException) {
// doesn't exist or can't be opened for writing
}

File.createNewFile() thowing IOException No such file or directory

I have a method that writes to a log file. If the file exists it should append to it, if not then I want it to create a new file.
if (!file.exists() && !file.createNewFile()) {
System.err.println("Error with output file: " + outFile
+ "\nCannot create new file.");
continue;
}
I have that to check that a file can be created. file is a java.io.File object. createNewFile is throwing an IOException: No such file or directory. This method has been working perfectly since I wrote it a few weeks ago and has only recently starting doing this although I don't know what I could have changed. I have checked, the directory exists and I have write permissions for it, but then I thought it should just return false if it can't make the file for any reason.
Is there anything that I am missing to get this working?
try to ensure the parent directory exists with:
file.getParentFile().mkdirs()
Perhaps the directory the file is being created in doesn't exist?
normally this is something you changed recently, first off your sample code is if not file exists and not create new file - you are trying to code away something - what is it?
Then, look at a directory listing to see if it actually exists and do a println / toString() on the file object and getMessage() on the exception, as well as print stack trace.
Then, start from zero knowledge again and re factor from the get-go each step you are using to get here. It's probably a duh you stuck in there somewhere while conceptualizing in code ( because it was working ) - you just retrace each step in detail, you will find it.
I think the exception you get is likely the result from the file check of the atomic method file.createNewFile(). The method can't check if the file does exist because some of the parent directories do not exist or you have no permissions to access them. I would suggest this:
if (file.getParentFile() != null && !file.getParentFile().mkDirs()) {
// handle permission problems here
}
// either no parent directories there or we have created missing directories
if (file.createNewFile() || file.isFile()) {
// ready to write your content
} else {
// handle directory here
}
If you take concurrency into account, all these checks are useless because in every case some other thread is able to create, delete or do anything else with your file. In this case you have to use file locks which I would not suggest doing ;)
According to the [java docs](http://java.sun.com/j2se/1.5.0/docs/api/java/io/File.html#createNewFile() ) createNewFile will create a new file atomically for you.
Atomically creates a new, empty file named by this abstract pathname if and only if a file with this name does not yet exist.
Given that createNewFile is atomic and won't over-write an existing file you can re-write your code as
try {
if(!file.createNewFile()) {
System.out.println("File already exists");
}
} catch (IOException ex) {
System.out.println(ex);
}
This may make any potential threading issues, race-conditions, etc, easier to spot.
You are certainly getting this Exception
'The system cannot find the path specified'
Just print 'file.getAbsoluteFile()' , this will let you know what is the file you wanted to create.
This exception will occur if the Directory where you are creating the file doesn't exist.
//Create New File if not present
if (!file.exists()) {
file.getParentFile().mkdirs();
file.createNewFile();
Log.e(TAG, "File Created");
}
This could be a threading issue (checking and creating together are not atomic: !file.exists() && !file.createNewFile()) or the "file" is already a directory.
Try (file.isFile()) :
if (file.exists() && !file.isFile()){
//handle directory is there
}else if(!file.createNewFile()) {
//as before
}
In my case was just a lack of permission:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Use
yourAppsMainActivityContext.getExternalCacheDir()
instead of
Environment.getExternalStorageDriectory()
to get the file storage path.
Alternatively, you can also try getExternalFilesDir(String type), getExternalCacheDir(), getExternalMediaDirs().

Categories