Search code examples
javaoptionaldataexception

Using readObject to get byte[][] giving OptionalDataException


I have a slight problem reading some files I have made. I am making a game and have decided to make my own file type for the maps. I have made a special application to make these map files. Once I instantiate a map I can choose to call readFile(String path) to set the map as the one saved. I know that I have to read and write the stream in the same order and everything went well until I added the statements about reading and writing the byte[][]. I cannot figure out why I am getting this exception and how to still read a byte[][]. Here is my class.

public class Map implements Serializable{

    String savePath;
    int boxWidth;
    int boxHeight;
    int mapWidth;
    int mapHeight;
    BufferedImage map;
    byte[][] encoded;
    LinkedList<BufferedImage> tileSet = new LinkedList<BufferedImage>();

    Map(int boxWidth, int boxHeight, int mapWidth, int mapHeight){
        map = new BufferedImage(boxWidth * mapWidth, boxHeight * mapHeight, BufferedImage.TYPE_INT_RGB);
        Graphics g = map.createGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, map.getWidth(), map.getHeight());
        g.dispose();
        this.boxHeight = boxHeight;
        this.boxWidth = boxWidth;
        this.mapHeight = mapHeight;
        this.mapWidth = mapWidth;
        initEncode();
    }

    Map(){
        map = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
        this.boxHeight = 0;
        this.boxWidth = 0;
        this.mapHeight = 0;
        this.mapWidth = 0;
        initEncode();
    }

    void initEncode(){
        int width = 2 * mapWidth + 1;
        int height = 2 * mapHeight + 1;
        encoded = new byte[width][height];
        for(int i = 0; i < width; i++){
            for(int j = 0; j < height; j++){
                encoded[i][j] = 0;
            }
        }
    }

    void setMapTile(int i, int j, byte index){
        encoded[2 * i + 1][2 * j + 1] = index;
    }

    void setMapWall(int i, int j, byte index){
        encoded[2 * i][2 * i] = index;
    }

    void addToTileset(Tile tile){
        tileSet.add(tile.tile);
        writeFile(savePath);
    }

    //writing to file with path - boolean is for whether it went successfully or not
    boolean writeFile(String path){
        savePath = path;
        try{
            OutputStream file = new FileOutputStream(path);
            OutputStream buffer = new BufferedOutputStream(file);
            ObjectOutputStream output = new ObjectOutputStream(buffer);

            writeObject(output);

            output.close();
            buffer.close();
            file.close();
        }catch(IOException ex){
            System.err.println("Could not Write to file: " + path + "\nError caused by: " + ex);
            return false;
        }
        return true;
    }

    //reading from file with path - boolean is for whether it went successfully or not
    boolean readFile(String path){
        savePath = path;
        try{
            InputStream file = new FileInputStream(path);
            InputStream buffer = new BufferedInputStream(file);
            ObjectInputStream in = new ObjectInputStream(buffer);

            readObject(in);
            initEncode();

            file.close();
            buffer.close();
            in.close();
        }catch(IOException ex){
            System.err.println("Could not read from file: " + path + "\nError caused by: " + ex + "\n");
            ex.printStackTrace();
            return false;
        }catch(ClassNotFoundException e){
            System.err.println("Could not read from file: " + path + "\nError caused by: " + e + "\n");
            e.printStackTrace();
        }
        return true;
    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        out.writeInt(boxHeight);
        out.writeInt(boxWidth);
        out.writeInt(mapHeight);
        out.writeInt(mapWidth);

        ImageIO.write(map, "png", out);
        out.writeObject(encoded);

        out.writeInt(tileSet.size());
        for(BufferedImage b: tileSet){
            ImageIO.write(b, "png", out);
         }
    }

    public void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
        boxHeight = in.readInt();
        boxWidth = in.readInt();
        mapHeight = in.readInt();
        mapWidth = in.readInt();

        map = ImageIO.read(in);
        encoded = (byte[][]) in.readObject();

        int tileSetSize = in.readInt();
        for(int i = 0; i < tileSetSize; i++){
            tileSet.add(ImageIO.read(in));
        }
    }
}

Is there some reason that my (byte[][]) readObject() line is throwing OptionalDataException and how do i still read/write my byte[][].

EDIT: Thank you for your answer Abhinav Kumar. I overlooked that but when I fixed the code it still gave me the same error on the same line. (The class has been fixed now).


Solution

  • You have to read the InputStream in the same order and same format which you write in the stream otherwise you would get OptionalDataException

    You have written the data in OutputStream in the order :-

            ImageIO.write(map, "png", out);
            out.writeInt(2 * mapWidth + 1);
            out.writeObject(encoded);
    

    And you are reading the stream in the order :-

            map = ImageIO.read(in);
            encoded = (byte[][]) in.readObject();
    

    Just read the int after u read map.The correct code would be :-

     public void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
            boxHeight = in.readInt();
            boxWidth = in.readInt();
            mapHeight = in.readInt();
            mapWidth = in.readInt();
            map = ImageIO.read(in);
            in.readInt();// you read this int and assign it to the object as you wish
            encoded = (byte[][]) in.readObject();
            int tileSetSize = in.readInt();
            for(int i = 0; i < tileSetSize; i++){
                tileSet.add(ImageIO.read(in));
            }
        }