FileWriter issue - unreported IOEXception which must be caught - java

I've encountered an issue in Java trying to write to a file using FileWriter. Simply declaring FileWriter writer = new FileWriter("filelocation"); yields that there is an unreported IOException which must be caught.
To rectify this, naturally I put my FileWriter within a try-catch block, but that causes an issue with scope. To fix this, I tried declaring the FileWriter before the try catch block and assigning the location within the try catch. After the try catch block when I would like to use the FileWriter, it tells me it may not have been initialized. I'm not certain how else to handle this, and never encountered this issue in Java 1.7 or likewise.
This is an example of my final situation in case I was unclear;
Scanner userInput = new Scanner(System.in);
FileWriter writer;
try {
System.out.println("Enter the file directory you would like to store in");
String fileLocation = userInput.nextLine();
writer = new FileWriter(fileLocation);
} catch(java.io.IOException e) {
System.out.println("Error message");
}
writer.write("Stuff"); //writer may not have been initialized

The good way :
System.console().printf("Enter the file directory you would like to store in");
String location = System.console().readLine();
try (FileWriter writer = new FileWriter (location)) {
writer.write("Stuff");
} catch (IOException e) {
new RuntimeException("Error message", e).printStackTrace();
}
Explanations:
System.console().printf() enable to print message on stdout. System.out may be prefered is having a "console" is not strictly required.
Uses System.console() for console management. Much easier and clearer. Don't forget to allocate a console (ie don't use javaw executable).
Opens stream using try-with-resources statement
printStackTrace() print on stderr the call stack which ease finding error location in code.
I have built a new Exception to attach your error message with the stack trace adds the "catch" location in the stack.
Advices:
Uses byte-stream for file access (ie FileOutputStream). It enables to enforce charset (ie OutputStreamWriter) and buffering (ie BufferedOutputStream or BufferedWriter).
Using byte-stream makes also possible to switch to NIO Channel API.
Uses StandardCharsets to access default (and largely commonly used) charset (Charsets that all JVM implementations must support)
Read The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
call to printStackTrace() isn't really nice and you should quickly introduce a logging system to print messages.
In case of a CLI, have good attention when using logging system to not confuse user about system interactions (ie prompt for user input) and feedbacks (ie progress message)

You say "naturally" you put it within a try-catch block. There's nothing natural about that, since there are two ways to handle it, and the other way is more common:
Handle the exception in a try-catch block.
Don't handle the exception, but declare that your method throws the exception, and allow it to cascade up the call stack.
Your code looks like it's in a main method, so you could add throws IOException:
public static void main(String[] args) throws IOException {
In your particular case, however, you're getting the file location from a user prompt, so rather than letting the program die with an error, the appropriate thing would be to tell the user about the error and prompt for a new name.
Also, remember to close your resources.
public static void main(String[] args) throws IOException {
Scanner userInput = new Scanner(System.in);
FileWriter writer;
do {
System.out.println("Enter the file name you would like to store in");
String fileLocation = userInput.nextLine();
if (fileLocation.trim().isEmpty())
return; // Exit program when user pressed enter with a name
try {
writer = new FileWriter(fileLocation);
} catch(java.io.IOException e) {
System.out.println("Cannot write to file: " + e);
writer = null;
}
} while (writer == null);
try {
writer.write("Stuff"); //writer may not have been initialized
} finally {
writer.close();
}
}
The write and the close can still technically throw an error (e.g. disk full), which we allow to cascade and kill the program.

Related

How, if possible, can one restrict generic exception messages from printing in the console?

The goal of the method below is to open a file and set a List of Strings equal to its lines before returning the List. If the file cannot be opened or read for whatever reason, I want to print the message, "Error reading ''..."
static List<String> readFile (String filename) {
System.out.println("Opening file \'" + filename + "\'...\n");
List<String> lines = null;
try {
Charset charset = Charset.forName("ISO-8859-1");
lines = Files.readAllLines(Paths.get(filename), charset);
}
finally {
catch (IOException e) {
System.out.println("Error reading \'" + filename + "\'...");
}
return lines;
}
I am executing the program in the Windows 10 command line with the file name as an argument. It works, but, in addition to my error message, another message is displayed to the console (by the JVM?). This is the command and output:
C:>java FileIO fake.txt
Opening file 'fake.txt'...
Error reading 'fake.txt'...fake.txt
Exception in thread "main" java.lang.NullPointerException
at FileIO.display(FileIO.java:35)
at FileIO.main(FileIO.java:14)
I am new to both Java and the Windows command line. I have some experience with C++ and Python in Linux terminals.
Is it possible to keep these messages from printing to the console or a different way to handle a bad file from the user? My understanding is that Files.readAllLines() requires the IOException.
I don't understand why the default is to assume the developer wouldn't create error messages to be displayed to the user. Or is the assumption that users don't run console applications and the only people who would see these exceptions are developers?
The problem is that you are catching the exception and pretending it didn't matter that it happened, i.e. you continue with a null value and try to display it when clearly that's not going to work.
You should only catch an exception when you are ready to deal with it. i.e. in the calling method.
public static void main(String... args) {
try {
List<String> lines = readFile(args[0]);
// don't try to display the lines of a file if it failed with an IOException
display(lines);
} catch(IOException ioe) {
System.err.println("Cannot display file " + ioe);
}
}
When you get an error, you should print out what it is as the error might be telling you something useful.
Note: this would be the best way to handle an exception even in C++.

Alternative ways to write a file in Java

I have next function:
static void write()
{
try {
File file = new File ("flip.out");
BufferedWriter out = new BufferedWriter(new FileWriter(file));
out.write(sMax);
System.out.println(sMax);//This command it works
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
The problem is that my program doesn't write anything in my file.
Few things to rectify -
Why create two different instances of File object
File file = new File ("flip.out");
BufferedWriter out = new BufferedWriter(new FileWriter("flip.out"));
All you need to do is
File file = new File ("flip.out");
BufferedWriter out = new BufferedWriter(new FileWriterfile(file ) ));
Next put your close call in finally statement rather than try block. Why? Because of IOException occurs resource will not be closed and if resource do not get closed your changes may not be reflected in the file.
Next it is a good programming practice not to catch Runtime exceptions. So do not use Exception as a ploymorphic type to catch your exception. Use whatever is being thrown like IOException in your case.
Now there might be various reasons why noting is being written in the file. As you are not getting and Exception one of the reason why this might be happening because your static function is not getting called or the string/object sMax(whatever that is) is empty.
Also the file(if not already present) will be created in the current directory. So if there are multiple instance is your code where your are creating files with same name then make sure you are checking the right one.
You have to flush the stream in order for what's in the memory to get written to the drive. What you wrote to BufferedWriter is sitting in a byte array waiting for the rest of it to be filled up before actually writing it to the disk. This helps with performance, but means you have to flush the stream in case you don't fill up that buffer. Here is how you do that:
static void write() throws IOException {
BufferedWriter out = new BufferedWriter(new FileWriter("flip.out"));
try {
out.write(sMax);
out.flush();
} catch (Exception e) {
// probably could ditch this and
// just the exception bubble up and
// handle it higher up.
e.printStackTrace();
} finally {
out.close();
}
}
So if it makes it to the flush() we know we wrote everything to the stream we wanted. However, if we ever get an exception we make sure we close the stream regardless of success or exception. And finally our stream is outside the try statement because the only exception ever thrown by Writers/OutputStreams during construction is FileNotFoundException which means the file never got opened in the first place so we don't have to close it.
can you call out.flush() before closing.
that will make sure any content in buffer is written to file immediately.

How to loop a try catch statement?

How do you loop a try/catch statement? I'm making a program that is reading in a file using a Scanner and it's reading it from the keyboard. So what I want is if the file does not exist, the program will say "This file does not exist please try again." then have the user type in a different file name. I have tried a couple different ways to try an do this but, all of my attempts end up with the program crashing.
Here is what I have
try {
System.out.println("Please enter the name of the file: ");
Scanner in = new Scanner(System.in);
File file = new File(in.next());
Scanner scan = new Scanner(file);
} catch (Exception e) {
e.printStackTrace();
System.out.println("File does not exist please try again. ");
}
If you want to retry after a failure, you need to put that code inside a loop; e.g. something like this:
boolean done = false;
while (!done) {
try {
...
done = true;
} catch (...) {
}
}
(A do-while is a slightly more elegant solution.)
However, it is BAD PRACTICE to catch Exception in this context. It will catch not only the exceptions that you are expecting to happen (e.g. IOException), but also unexpected ones, like NullPointerException and so on that are symptoms of a bug in your program.
Best practice is to catch the exceptions that you are expecting (and can handle), and allow any others to propagate. In your particular case, catching FileNotFoundException is sufficient. (That is what the Scanner(File) constructor declares.) If you weren't using a Scanner for your input, you might need to catch IOException instead.
I must correct a serious mistake in the top-voted answer.
do {
....
} while (!file.exists());
This is incorrect because testing that the file exists is not sufficient:
the file might exist but the user doesn't have permission to read it,
the file might exist but be a directory,
the file might exist but be unopenable due to hard disc error, or similar
the file might be deleted/unlinked/renamed between the exists() test succeeding and the subsequent attempt to open it.
Note that:
File.exists() ONLY tests that a file system object exists with the specified path, not that it is actually a file, or that the user has read or write access to it.
There is no way to test if an I/O operation is going to fail due to an hard disc errors, network drive errors and so on.
There is no solution to the open vs deleted/unlinked/renamed race condition. While it is rare in normal usage, this kind of bug can be targeted if the file in question is security critical.
The correct approach is to simply attempt to open the file, and catch and handle the IOException if it happens. It is simpler and more robust, and probably faster. And for those who would say that exceptions should not be used for "normal flow control", this isn't normal flow control ...
Instead of using a try catch block, try a do while loop checking if the file exists.
do {
} while ( !file.exists() );
This method is in java.io.File
You can simply wrap it in a loop:
while(...){
try{
} catch(Exception e) {
}
}
However, catching every exception and just assuming that it is due to the file not existing is probably not the best way of going about that.
Try something like this:
boolean success = false;
while (!success)
{
try {
System.out.println("Please enter the name of the file: ");
Scanner in = new Scanner(System.in);
File file = new File(in.next());
Scanner scan = new Scanner(file);
success = true;
} catch (FileNotFoundException e) {
e.printStackTrace();
System.out.println("File does not exist please try again. ");
}
}
Check if the file exists using the API.
String filename = "";
while(!(new File(filename)).exists())
{
if(!filename.equals("")) System.out.println("This file does not exist.");
System.out.println("Please enter the name of the file: ");
Scanner in = new Scanner(System.in);
filename = new String(in.next();
}
File file = new File(filename);
Scanner scan = new Scanner(file);

Write-to-file code doesn't write

Well, I am trying to write a line of information to log in a text file (.txt) but this is the part where the code fails to write. Everything else works, except this but doesn't give any errors.
public void writeConfig(File config, Boolean append, String errored){
try {
Writer output;
if (config != null){
output = new BufferedWriter(new FileWriter(config));
} else {
output = new BufferedWriter(new FileWriter(er));
}
if (append == true){
output.append(errored);
} else {
output.write(errored);
}
} catch (Exception e){
try {
loadErrorLog(error, true, "Failed to write to Boom's Log.\n");
} catch (Exception e1){
log.info("Major Malfunction #686 : Tell Maker immediatly.");
}
}
}
You're not closing the writer, which means all the data is just staying in the buffer.
You should close it in a finally block.
Additionally:
your use of the append parameter is distinctly dodgy - you should almost certainly be passing it to the constructor of the FileWriter (or FileOutputStream). I don't think append in Writer does what you think it does.
Try to avoid comparing with true - just if (append) would have been clearer
Using the conditional operator could make your FileWriter code cleaner, especially if you used it just for the file:
File file = config == null ? er : config;
Writer writer = new BufferedWriter(new FileWriter(file));
I would avoid using FileWriter in the first place, as it always uses the platform default encoding. Use a FileOutputStream wrapped in an OutputStreamWriter instead, specifying the encoding explicitly (e.g. UTF-8)
Avoid catching Exception in most places; here it would be cleaner to just catch IOException.
It looks like your loadErrorLog method should probably be doing that logging on failure, otherwise I suspect you'll be writing that block of code every time you call it.
Do you really want to continue if you fail to write the config? Is it definitely this method which should handle the exception? I'd potentially remove the catch block entirely (leaving just a try/finally) and let the IOException bubble up the stack

Java, what to use instead of PrintStream to get exceptions?

I am creating a file on a network drive and then adding data to it. Time to time writing to that file fails. Is there a good way of checking if the file is accessible before every time i save data to it or maybe is tehre a way checking afther to see if the data was saved?
EDIT:
Right now i am using try-catch block with PrintStream in my code:
try
{
logfile = new File(new File(isic_log), "log_" + production);
//nasty workaround - we'll have a file the moment we assign an output stream to it
if (!logfile.exists())
{
prodrow = production;
}
out = new FileOutputStream(logfile.getPath(), logfile.exists());
p = new PrintStream(out);
if (prodrow != "")
{
p.println (prodrow);
}
p.println (chip_code + ":" + isic_number);
p.close();
}
catch (Exception e)
{
logger.info("Got exception while writing to isic production log: " + e.getMessage());
}
So might be the PrintStream the problem? (PrintWriter and PrintStream never throw IOExceptions)
I would use plain BufferedWriter and add the newlines myself as required.
Normal FileOutputStream operations should throw an IOException if there is an error.
AFAIK, The only exception is PrintWriter which does not throw an exception. Instead you need to call checkError() but it gives you no indication of what the error was or when it occurred.
I suggest you not use PrintWriter in this situation.
The only reasonable way to address this is to try to write to the file, and handle any resulting exception in an appropriate manner. It's pretty much impossible to know beforehand whether an I/O operation is going to succeed, due to the unreliable nature of networks.

Categories

Resources