ShadowEagle ShadowEagle - 2 months ago 6
Java Question

Java - Can't write object as file to directory

I have a weird problem with my program.
I wrote a small program to write an object to a file in a specific directory.

Player-Class:

package readwrite;

import java.io.Serializable;

public class Player implements Serializable {

private String name;
private int level;

public Player(String name, int level) {
this.name = name;
this.level = level;
}

public String getName() {
return name;
}

public int getLevel() {
return level;
}

public void setName(String name) {
this.name = name;
}

public void setLevel(int level) {
this.level = level;
}

public String toString() {
return "Name: " + name + ", Level: " + level;
}

public void printInfo() {
System.out.println(this.toString());
}

}


PlayerReaderWriter-Class:

package readwrite;

import java.io.*;

public class PlayerReaderWriter {

public static Player readPlayer(String path) {
Player p = null;

try {
FileInputStream fileIn = new FileInputStream(path);
ObjectInputStream in = new ObjectInputStream(fileIn);
p = (Player) in.readObject();
in.close();
fileIn.close();
} catch(IOException | ClassNotFoundException e) {
e.printStackTrace();
}

return p;
}

public static void writePlayer(String path, Player p) {
try {
File file = new File(path);
if (file.exists()) {
file.delete();
file.createNewFile();
} else {
file.mkdirs();
file.createNewFile();
}

FileOutputStream fileOut = new FileOutputStream(path);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(p);
out.close();
fileOut.close();
} catch(IOException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
Player p = new Player("Foo", 64);
p.printInfo();
writePlayer("players/Player.ser", p);

Player q = readPlayer("players/Player.ser");
q.printInfo();
}

}


The problem is: When I run my program for the first time, when the directory "players" doesn't exist, I get the following error:

D:\Projects>java readwrite/PlayerReaderWriter
Name: Foo, Level: 64
java.io.FileNotFoundException: players\Player.ser (Access is denied)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(FileOutputStream.java:270)
at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
at readwrite.PlayerReaderWriter.writePlayer(PlayerReaderWriter.java:34)
at readwrite.PlayerReaderWriter.main(PlayerReaderWriter.java:47)
java.io.FileNotFoundException: players\Player.ser (Access is deniedt)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at readwrite.PlayerReaderWriter.readPlayer(PlayerReaderWriter.java:11)
at readwrite.PlayerReaderWriter.main(PlayerReaderWriter.java:49)
Exception in thread "main" java.lang.NullPointerException
at readwrite.PlayerReaderWriter.main(PlayerReaderWriter.java:50)


Now the directory "players" has been created by the program and for some reason it also created a subdirectory named "Player.ser".

When I run it a second time, it works and creates a "Player.ser" file within the "players" directory.

When I run it with just a empty directory named "players" it also won't work.

Regards :)

Answer

Look at this code:

if (file.exists()) {
    file.delete();
    file.createNewFile();
} else {
    file.mkdirs();
    file.createNewFile();
}

You're saying that if players/Player.ser doesn't exist, you should create it as a directory - and then also as a file. That's broken.

You don't need to delete the file at all if it already exists - you can just use a FileOutputStream and let it overwrite the file, truncating it to start with, as is the default behaviour.

You just need to check whether the directory exists first, e.g.

File file = new File(path);
File parent = file.getParentFile();
// TODO: Handle parent existing, but not being a directory,
// or file existing, but being a directory...
if (!parent.exists()) {
    parent.mkdirs();
}

try (OutputStream output = new FileOutputStream(file)) {
    // ...
}

Note the try-with-resources statement so that your output stream is always closed even if an exception is thrown.