1

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 :)

ShadowEagle
  • 439
  • 1
  • 4
  • 14
  • 1
    I believe you get what you’re asking for. :-) First time, the file does not exist, so your program does file.mkdirs() — this create directory players and *directory* Player.ser. Next time the directory Player.ser exists (you didn’t ask if it was a directory, only if it existed), so your program deletes the directory and creates a file instead. With just an empty players directory you get the first behaviour except the players directory isn’t created since it is already there, the rest is the same. BTW you ought to have been able to reproduce the behaviour in a much smaller example. :-) – Ole V.V. Jun 07 '16 at 16:00

2 Answers2

6

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.

Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
1

Have a look at the JavaDoc on File#mkdirs():

Creates the directory named by this abstract pathname ...

That says that the file is assumed to represent a directory, hence Player.ser is created as a directory. Use file.getParentFile().mkdirs() instead (keep in mind that depending on the path there might be no parent).

Since your code is creating a directory any write operation to that File object will fail since you can't write data directly into a directory.

Thomas
  • 80,843
  • 12
  • 111
  • 143