Search code examples
javaioexception

how to get the filename of a thrown IOException in java?


I have a try block which handles quite a few file opening/closing/reading/writing (more than one file).

It looks like:

try {
    // commands
}
catch (IOException e) {
    System.err.println("Error: " + e);
}

The main problem is that e.toString() does not contain information about the filename for which the exception was thrown, if there is an error.

I could check each read/write/open/close operation separately, and then know which file the error happens with, but that seems to defeat the purpose of having the elegant try-catch structure.

Is there any other way out? I just want to be able to print the file name for which e had the error in the try block.

EDIT: Maybe I should make it clear in which scenario this issue arises. This happens when I parse command-line arguments, input/output files, etc. I pass the file names to various functions and methods that can return with an IO error. It seems reasonable to require that I would have a generic way of handling any file problem by printing the error and the filename that had that error. I understand that IOException is more broad than handling IO with files, but surely it makes sense, given that IOException is a specialized exception class, to have a method that returns the IO source for which the error occurred.


Solution

  • You don't - as you know, IOException doesn't have information about the File that generated the exception. It's purpose it too general. If you roll your own, you can capture relevant information and catch your own exception instead.

    In the various methods that handle your input, wrap the relevant section in try/catch blocks, catch the IOException, and throw your own with the additional data.

    Here is a complete program that demonstrates the basic idea.

    class FooException extends Exception { 
        private static final long serialVersionUID = 2816777468035627105L;
        private final String filename; 
        private final Throwable cause; 
    
        public FooException(String filename) { 
            this(filename, null); 
        }
    
        public FooException(String filename, Throwable cause) { 
            this.filename = filename; 
            this.cause = cause; 
        }
    
        @Override
        public String getMessage() { 
            return "Error reading file"; 
        }
    
        @Override
        public Throwable getCause() {
            return cause; 
        }
    
        public String getFilename() { 
            return filename; 
        }
    }
    
    public class Soj25375647 {    
        public static void main(String[] args) {
             try {
                 throwsAnException();
                 // Do other things that might throw my exception
             } catch (FooException e) { 
                 System.err.printf("File: %s, error: %s, caused by %s%n", e.getFilename(), e, e.getCause());
             }
        }
    
        public static void throwsAnException() throws FooException { 
            try { 
                int x = 2 / 0;
            } catch (ArithmeticException e) { 
                throw new FooException("bob.file", e);   
            }
        }
    }
    

    Output

    File: bob.file, error: soj25375647.FooException: Error reading file, caused by java.lang.ArithmeticException: / by zero
    

    See Also Exception-Handling Antipatterns.