Search code examples
javajava-ioioexceptionjavax.imageio

Getting java.io.IOException: closed whenever I close my program


Every time I run my program it runs fine. But when I close it after running the program for a few seconds, then I get the java.io.IOException: closed error. I've tried looking around and couldn't find a solution. The only fix I could find was just not using the e.printstacktrace in the try-catch block, but that obviously doesn't fix the issue. Here is the code:

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import javax.imageio.ImageIO;

public class Main extends Canvas implements Runnable
{
    private static final long serialVersionUID = -661485289446387445L;
    private Thread thread;
    public int blackPos;
    public int whitePos;
    public boolean isWhiteTurn; // In single player this determines board orientation, in multiplayer it doesn't
    public boolean running;
    public final int HEIGHT = 800;
    public final int WIDTH = 1200;
    //public File[] imgSrc = {new File("/images/urBoard.png"), new File("/rsc/urBackground.jpg")};
    public BufferedImage[] img = new BufferedImage[2];
    public Board board;

    public Main()
    {
        new Window(WIDTH, HEIGHT, this);
        board = new Board(this);
    }

    public void run()
    {
        requestFocus();
        long lastTime = System.nanoTime();
        double amountOfTicks = 60.0D;
        double ns = 1.0E9D / amountOfTicks;
        double delta = 0.0D;
        long timer = System.currentTimeMillis();
        int frames = 0;
        while (this.running)
        {
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            lastTime = now;
            while (delta >= 1.0D)
            {
                tick();
                delta -= 1.0D;
            }
            if (this.running) {
                render();
            }
            frames++;
            if (System.currentTimeMillis() - timer > 1000L)
            {
                timer += 1000L;
                System.out.println("FPS: " + frames);
                frames = frames;
                frames = 0;
            }
        }
    }

    public synchronized void start()
    {
        thread = new Thread(this);
        thread.start();
        running = true;
    }

    public synchronized void stop()
    {
        try
        {
            this.thread.join();
            this.running = false;
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public void tick()
    {
        board.tick();
    }

    public void render()
    {
        BufferStrategy bs = getBufferStrategy();
        if(bs == null)
        {
            createBufferStrategy(3);
            return;
        }

        try
        {
            img[0] = ImageIO.read(getClass().getResource("/rsc/urBoard.png"));
            img[1] = ImageIO.read(getClass().getResource("/rsc/urBackground.jpg"));
        }
        catch (IOException e) {
            e.printStackTrace();
        }

        Graphics g = bs.getDrawGraphics();

        g.drawImage(img[1], 0, 0, WIDTH, HEIGHT, null);
        g.setColor(Color.GREEN);
        g.drawLine(200, 0, 200, 800);
        g.setFont(new Font("times new roman", Font.BOLD, 30));
        g.drawString("END PIECES", 10, 30);

        board.render(g);

        g.dispose();
        bs.show();
    }

    public static void main(String[] args)
    {
        new Main();
    }

}

And here is the error that I get whenever I close the GUI after it has ran for a couple of seconds:

java.io.IOException: closed
    at javax.imageio.stream.ImageInputStreamImpl.checkClosed(ImageInputStreamImpl.java:110)
    at javax.imageio.stream.ImageInputStreamImpl.close(ImageInputStreamImpl.java:857)
    at javax.imageio.stream.FileCacheImageInputStream.close(FileCacheImageInputStream.java:250)
    at javax.imageio.ImageIO.read(ImageIO.java:1451)
    at javax.imageio.ImageIO.read(ImageIO.java:1400)
    at main.Main.render(Main.java:99)
    at main.Main.run(Main.java:54)
    at java.lang.Thread.run(Thread.java:745)

I've noticed that if I close the window right after I start the program the error doesn't come. It only comes when I've run the program for about 3-4 seconds, and then I close the window. What would cause this to happen, and what would be the fix?


Solution

  • It looks like your render() method may be running when closing the app. As your resources aren't changing between render() calls, move this block to the start of the Main() constructor so that img[] is set up once, and throws an exception if resources are not found:

    try {
        img[0] = ImageIO.read(getClass().getResource("/rsc/urBoard.png"));
        img[1] = ImageIO.read(getClass().getResource("/rsc/urBackground.jpg"));
    } catch (IOException e) {
        throw new RuntimeException("Could not find resources");
    }
    

    The field running is used in different threads so it should be marked volatile in order that each thread reads consistent values:

    public volatile boolean running;