JUnit and file write access - java

So I have a method to write a string to a file:
public static void saveStringToFile(String path, String string) {
File file = new File(path);
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
FileWriter out = null;
try {
out = new FileWriter(path);
out.write(string);
if (out != null) {
out.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
And my test class with the following setUp method which runs before each test (to delete the testfile before each one):
public static final String TEST_FILE = "somefile.xml";
//...
#Before
public void setUp() throws IOException {
if (MyCustomClass.fileExists(TEST_FILE)) {
new File(TEST_FILE).delete();
}
}
Each of my test tries to write something to the file using the method saveStringToFile(). It succeeds like for a couple of times, but a some random point I finally get the java.io.IOException: Access is denied. Got no idea why this happens - sometimes it occurs in test1, sometimes in test3...
It was working OK, when I was using Java7 FileIO, but I needed to migrate back to Java6...

Are you testing that you are able to create, write to and delete a file, or are you testing what is written to the file?
If the latter, then perhaps you should be mocking/overriding the saveStringToFile( ... ) method and instead focus on verifying that the code you're unit testing actually produces the correct output.
If the former, then I quite agree with #Omaha's suggestion that your test runner is likely running several tests in parallel.
Hope that helps.

There's some problems with the exception handling. The call to out.close() should be within a separate try-catch block inside a finally block. If an exception is thrown when writing to the file, the file is never closed.
I would recommend looking at something like Apache Commons IO which has many useful IO methods like FileUtils.writeStringToFile().

So, probably JUnit wasn't running it parrallel, cause as I suppose It doesn't do it by default.
The problem was in my readfile method:
private String readFile(String path) throws FileNotFoundException {
return (new Scanner(new File(path))).useDelimiter("\\Z").next();
}
To work fine I had to fix
private String readFile(String path) throws FileNotFoundException {
Scanner scanner = (new Scanner(new File(path)));
String s = scanner.useDelimiter("\\Z").next();
scanner.close();
return s;
}
The close() method for Scanner was the key...

Related

Can't get JUnit test to fail (it should)

I have the following code in a JUnit test (only including the relevant parts)
private String testRoot = System.getProperty("user.home");
private String destFail2 = testRoot + "/GoogleDrive/TestFail//..\\...//*";
#Test
public void given_NamedParameterizedFileSet_when_SavedWithInvalidFileName_then_Exception() {
String invalidFullPathToFileSet = fsPathDir + invalidBackupName;
//test save fully parameterized empty file set at non-existent directory
try {
FileSet fs = new FileSet(backupName, dest);
try {
FileSet.save(invalidFullPathToFileSet, fs);
fail("Save name is invalid, should refuse save");
} catch (IOException e) {
assert(true);
}
} catch (Exception e1) {
e1.printStackTrace();
fail("Could not create the file set");
}
}
The code for FileSet.save() is as follows:
public static void save(String fullPathToFile, FileSet fileSet) throws IOException {
ObjectOutputStream out = null;
Path outFilePath = Paths.get(fullPathToFile);
Path outDirPath = outFilePath.getParent();
if (Files.exists(outFilePath)) {
Files.delete(outFilePath);
}
if (!Files.exists(outDirPath)) {
Files.createDirectories(outDirPath);
}
try {
out = new ObjectOutputStream(new
BufferedOutputStream(Files.newOutputStream(outFilePath)));
out.writeObject(fileSet);
} catch (Exception e) {
e.printStackTrace();
} finally {
out.close();
}
}
The FileSet.save() method above SHOULD fail because it's being given what I think is an invalid file name, but somehow the code runs just fine without throwing an exception (on a Mac; haven't tried it on Windows).
Why is the code running?
Given the code, where do I look for the file it created?
What kind of filename do I need that is "bad?" I tried creating one with a colon (:) in it as it's supposed to be the only illegal character on a Mac, but even that works and it ends up creating a file with a colon in the middle of the name...
Is there a "better" way to write FileSet.save() (rather than using Path, should I be using File and passing the path in to the constructor as a string)?
Firstly, don't use assert keyword - if you run the java application without -ea parameter ("enable assertions"), this line will not execute at all. By the way assert true does nothing.
Secondly, exceptions that you do not care about, those that you are not testing, like e1 shouldn't be caught, declare that test method throws it. It will reduce the unnecessary complexity.
Finally, I would recommend using ExpectedException to do this assertion:
#Rule
public final ExpectedException expectedException = ExpectedException.none();
#Test
public void given_NamedParameterizedFileSet_when_SavedWithInvalidFileName_then_Exception() throws Exception {
String invalidFullPathToFileSet = fsPathDir + invalidBackupName;
FileSet fs = new FileSet(backupName, dest);
expectedException.expect(IOException.class);
FileSet.save(invalidFullPathToFileSet, fs);
}
This allows you to also check a message. It also checks that the exception is thrown after expect line. So if new FileSet(...) throws IOException, the test will fail. Note, ExpectedException needs to be annotated as #Rule to let junit now to perform a check at the end of test.
The test is successful because of improper exception handling. In the inner try-catch:
try {
FileSet.save(invalidFullPathToFileSet, fs);
fail("Save name is invalid, should refuse save");
} catch (IOException e) {
assert(true);
}
The line FileSet.save(invalidFullPathToFileSet, fs); throws an exception and for this reason the next line, which should fail the test, is not executed and the execution flow is redirected to the catch block where you simply assert(true) (which is a completely useless statement in a unit test) and then exit the inner and then the outer try-catch blocks, leading to successful execution.
What you should do is something like:
try {
FileSet.save(invalidFullPathToFileSet, fs);
} catch (IOException e) {
e.printStackTrace();
fail("Save name is invalid, should refuse save");
}
This will fail the test whenever an exception is thrown.

calling a function: unreported IOException must be declared to be thrown

I have this code but there is an error to this,
I am not good with java so I posted my problem in here... this is my code
public static void SaveFile() throws IOException{
System.out.println("Saving File!");
FileWriter toTextFile = new FileWriter("output.txt");
for(x=0;x<new_num_book;x++){
toTextFile.write(name[x]);
}
toTextFile.close();
}
blah blah
else if(option == 5){
SaveFile();
}
the problem is that netbeans declares an error in accessing the SaveFile function. Please help! Thanks
saveFile throws an IOException, you need to handle it or pass it on to the caller.
Take a look at The try Block for more details
Without more context it's hard to say what you should do. You could handle the exception within the current method...
else if(option == 5){
try {
SaveFile();
} catch (IOException exp) {
// Handle the exception, tell the user, roll back, what ever
// At the very least use exp.printStackTrace()
}
}
or declare the current method as throwing an IOException like the SaveFile method does
Your SaveFile method is also, potentially, leaving the file open...
If the file writing process fails for some reason, toTextFile.close may never be called, instead, you should take advantage of the try-finally block, for example
public static void SaveFile() throws IOException{
System.out.println("Saving File!");
FileWriter toTextFile = null;
try {
toTextFile = new FileWriter("output.txt");
for(x=0;x<new_num_book;x++){
toTextFile.write(name[x]);
}
} finally {
try {
toTextFile.close();
} catch (Exception exp) {
}
}
}
or if you're using Java 7+, you can make use of the try-with-resources functionality, for example...
public static void SaveFile() throws IOException{
System.out.println("Saving File!");
try (FileWriter toTextFile = new FileWriter("output.txt")) {
for(x=0;x<new_num_book;x++){
toTextFile.write(name[x]);
}
}
}
You may also want to have a read of Lesson: Exceptions and Code Conventions for the Java TM Programming Language, which will make it easier for people to read your code and for you to read others

Java: Writing to a log file from a server

Im trying to create a log file for a small chatroom I've created.
so far this is what I have for the logging:
static void log(String s){
try{
BufferedWriter writer =
new BufferedWriter(new FileWriter("log"+getTime()+".txt"));
writer.write(s);
}catch(IOException e){
e.printStackTrace();
}
}
I call it in this way in a thread for each connection each time I brodcast to the clients:
log(name+"String")
but after its called and doesn't continue the program. however, when this did work, the only thing in the text file would be one line, the first one called. how can one fix both these bugs?
As stated in the other answers, you don't close the file and you are not writing a line separator.
I see that there's one perfect answer in Java 7, but you said in the comments that you are not able to use that. (I suppose you are using Java 6 instead)
Because of that, I have written an implementation using only Java 6 API (using the Java 6 javadocs for reference):
public class LogFileHelper {
private final BufferedWriter writer;
public LogFileHelper(File outputFile) throws IOException {
if(!outputFile.exists()){ //The JavaDoc says that it is not certain if the file will be created
outputFile.createNewFile();
}
this.writer = new BufferedWriter(new FileWriter(outputFile, true));
}
public void writeLine(String line) throws IOException {
if(line == null){
throw new IllegalArgumentException("line may not be null");
}
this.writer.write(line);
this.writer.newLine();
this.writer.flush(); //Make sure the line we just wrote is written and kept if the application crashes
}
public void tryWriteLine(String line) {
try {
writeLine(line);
} catch(IOException ioe){
//Your exception handling here
}
}
public void close() throws IOException {
this.writer.close();
}
public void tryClose() {
try {
this.writer.close();
} catch(IOException ioe){
//Your exception handling here
}
}
}
I added tryXXX methods to simplify exception handling, as I suppose you will use the same everywhere. I kept the base methods to allow for custom exception handling where needed.
With above class, you would store the instance somewhere, write to it where needed and close it on exit. Your best bet for that is a shutdown handler like this one:
Runtime.getRuntime().addShutdownHook(new Thread("Chatlog Shutdown Thread"){
#Override
public void run(){
myLogFileHelper.tryClose();
}
});
Where you would execute that statement just after you create your LogFileHelper instance.
The above code does flush every time you write something - If you want to go super efficient, you could flush less often. A valid use case for not flushing immediately would be when writing a whole batch of lines at once, although you always have to balance between not flushing and having the file on disk immediately.
Use try-with-resources and write in append mode:
static void log(String s) {
try (PrintWriter out = new PrintWriter(new BufferedWriter(
new FileWriter("log" + getTime() + ".txt", true)))) {
out.println(s);
} catch (IOException e) {
e.printStackTrace();
}
}
You have several problems:
each time you log one statement you open a new file descriptor;
... which you don't close;
given on the output of .getTime() you may even write to several different files.
Use a dedicated class which you initialize and share once across all classes which use logging facilities; for instance a singleton.
In the constructor you would open the file:
private final BufferedWriter writer;
// ...
public MyLogFile()
throws IOException
{
final Path path = Paths.get("path to logfile");
writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8,
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
}
Use a method to write a line:
public void writeOneLine(#Nonnull final String line)
throws IOException
{
Objects.requireNonNull(line, "won't write null, sorry");
writer.write(line);
writer.newLine();
writer.flush();
}
As for closing the file when you exit, either make you class implement Closeable and .close() it when your program ends (or even AutoCloseable) or add a JVM shutdown hook.

Can't delete the file after writing some data to it, where is wrong?

I'm write some text a file then delete it, but the deletion is failed.
The code is very simple:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class TestFile {
public static void main(String[] args) throws IOException {
File file = new File("c:\\abc.txt");
writeFile(file, "hello");
// delete the file
boolean deleted = file.delete();
System.out.println("Deleted? " + deleted);
}
public static void writeFile(File file, String content) throws IOException {
OutputStream out = null;
try {
out = new FileOutputStream(file);
out.write(content.getBytes("UTF-8"));
} catch (IOException e) {
try {
out.close();
} catch (IOException e1) {
// ignored
}
}
}
}
The output is:
Deleted? false
And there is a file abc.txt contains hello still there under c:.
Then I use FileUtils.writeStringToFile(...) from commons-io.jar instead, the file will be deleted.
But I don't know where is wrong with my code, please help me to find it out.
You are only closing the file if you get an IOException.
Change it to a finally block and you will be able to close and delete the file.
public static void writeFile(File file, String content) throws IOException {
OutputStream out = new FileOutputStream(file);
try {
out.write(content.getBytes("UTF-8"));
} finally {
try {
out.close();
} catch (IOException ignored) {
}
}
}
You need to close your OutputStream when you finished writing the file.
try {
out = new FileOutputStream(file);
out.write(content.getBytes("UTF-8"));
out.close();
} catch (IOException e) {
try {
out.close();
} catch (IOException e1) {
// ignored
}
}
In your main method,
public static void main(String[] args) throws IOException {
File file = new File("c:\\abc.txt");
writeFile(file, "hello");
// delete the file
boolean deleted = file.delete();
System.out.println("Deleted? " + deleted);
}
You open the file, write to it and then do not close it. Java keeps the file open for you, so if you wanted to add more information to it, you could. However, to be able to delete the file, you need to make sure no other reference is open to it. You can do this by using file.close() to close the file handle Java reserves for you.
It's best practice to always close a stream when you are done with it, especially if you added data to it. Otherwise, you might run into situations where you are keepings files open by accident, or, in extreme cases, lose data you thought was saved already.
Have a look at what FileUtils.writeStringToFile() does that you haven't.
public static void writeStringToFile(File file, String data, String encoding) throws IOException {
OutputStream out = new java.io.FileOutputStream(file);
try {
out.write(data.getBytes(encoding));
} finally {
IOUtils.closeQuietly(out);
}
}
You will note that the out stream is always closed, wheras in your example it only gets closed in your catch block if the write() throws an exception.
On Windows, files that are open by any program cannot be deleted.
You just delete your file if an exception occurs. You need to do that every time, after you opened the file.
You may want to put close into a finally block.
If you're using Java 7 I consider using a try-with-ressources block, which takes care of closing files for you.
try (BufferedReader br = new BufferedReader(new FileReader(path)))
{
return br.readLine();
}

Assistance in writing my file writer method for a servlet

I have a simple servlet where I write to a file if it has a queryparameter 'hello', and since this is a test I want to display the error the the webpage also.
IntelliJ is complaining that I am not catching the IOException, not sure what's wrong:
private static void WriteToFile(String filePath, String fileName, String fileData) {
FileWriter writer = null;
try {
writer = new FileWriter(fileName);
writer.write(fileData);
} catch(IOException ex) {
} finally {
if(writer != null) {
writer.close();
}
}
}
Also, in my exception, I noticed on the web most people write:
How can I output the error to the web page?
You're not catching IOException when you call writer.close(); in the finally block.
You're also completely swallowing any IOException thrown in the main code, which is a really bad idea. If something's goes wrong, you'll have no idea what's happening.
I would personally suggest that you let that method throw the exception to the caller:
private static void writeToFile(String filePath, String fileName,
String fileData) throws IOException {
FileWriter writer = new FileWriter(fileName);
try {
writer.write(fileData);
} finally {
writer.close();
}
}
Note that if the try block throws an exception and the finally block does, you'll effectively "lose" the original exception. You may want to suppress exceptions throw when closing.
Or just use Guava which makes all of this simpler anyway with its Files class.
Or if you're using Java 7, you could use a try-with-resources statement.
(I note that you're ignoring filePath by the way - why?)
You can write in catch block too : writer.write(errorMessage);
or you may redirect to Error page if error occured

Categories