开发者

How do I open, write and save a file while avoiding errors?

I need to erase a file in my program. My solution was to have an era开发者_如何学Cse() method that would do that like so:

public static void erase(String string) {
    FileWriter fw = null;
    try {
        fw  = new FileWriter(string);
        fw.write(new String());
    } catch (IOException ie) {
        e.printStackTrace();
    } finally {
        fw.flush();
        fw.close(); 
    }
}

Several problems here:

  • If the fw does not properly initialize (for whatever reason, missing file, invalid persmissions, etc) then when I try to close it in the finally block, there is a NullPointerException.

  • If I don't have the finally block, then I might be throwing a NullPointerException for the reason above.

  • If I close the file inside the try block, then I might leak the resource if the file properly opens, but doesn't properly write.

What other problems am I overlooking and how can I harden this method?


You can just wrap the finally functionality in an if-statement:

if(fw != null){
    fw.close(); 
}

This will ensure that if the file was ever opened, then it will be closed. If it wasn't opened in the first place, then it won't do anything, which is what you want.

Also, I'm not sure if it's just like that for posting, but it's generally not advisable to just print a stacktrace in a catch block and continue ("swallowing" the exception). You really should let the exception get thrown because this could hide bugs and make tracking them down very hard.

EDIT: See comment below.


To the best of my knowledge, this is the correct idiomatic way to write your code:

FileWriter fw = new FileWriter(string);
try {
    fw.write(new String());
    fw.flush();
} catch (IOException ie) {
    ie.printStackTrace();
} finally {
    fw.close(); 
}

Explanation:

  • If new FileWriter() throws an exception, then we don't need to clean up anything. The method exits without executing the finally.
  • We should put fw.flush() in the try, not in the finally. There are two reasons: If the write failed, then we shouldn't bother flushing. Also, if you put the flush() in finally and it throws an exception, then the close() will be skipped.


Include the flush() in your main block and have only the close() in the catch. Then check for null before closing:

finally {
    if(fw!=null) { fw.close(); }
    }

With the flush in the main block, you can also try/catch the close and log or ignore any error:

finally {
    if(fw!=null) { 
        try { fw.close(); } catch(Throwable thr) { log.printError("Close failed: "+thr); thr.printStackTrace(); } 
        }
    }

or (not generally recommended):

finally {
    try { fw.close(); } catch(Throwable thr) {;}
    }

EDIT

The best general Java idiom for handling I/O, IMO, is:

FileWriter fw=null;
try {
    fw=new FileWriter(string);
    fw.write(new String());
    fw.close();
    fw=null;
    }
catch(IOException ie) {
    // do something real here to handle the exception, or don't catch it at all.
    } 
finally {
    if(fw!=null) { 
        try { fw.close(); } catch(Throwable thr) { thr.printStackTrace(); } // now we're really out of options
        }
    }    

This has the important effect of allowing the catch to catch and handle an exception thrown by close() itself. (The catch clause should only be present if you can handle the exception in some way; do NOT catch and ignore, and generally you should not simply catch and trace.)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜