ImageIO关闭了InputStream

4

我在使用ImageIO时遇到了一个非常奇怪的问题。

我的Java程序中有几个对象拥有一张图片。我通过我的ImageManager中的静态方法load来加载这些图片。

public static Image load(String path){
    Image img = null;
    try {
        img = ImageIO.read(ImageManager.class.getResource(path));
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    if(img == null){
        System.out.println("Image: '" + path + "' not found!");
    }

    return img;
}

每当我加载(静态)背景图像或在我的渲染方法中加载图像时,没有问题。
同样,当将图像加载到我的Card类的静态变量中时,也没有问题。但是,一旦我从我的Card构造函数动态加载图像,就会抛出异常,说流已关闭。
java.io.IOException: closed
Image: '/textures/cards/back.png' not found!
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 visual.gfx.ImageManager.load(ImageManager.java:15)
at visual.Card.<init>(Card.java:49)
at visual.WorldController.render(WorldController.java:98)
at visual.WorldController.run(WorldController.java:116)
at java.lang.Thread.run(Thread.java:745)

所以明确一点: 这个:
public class Card{
    public static Image BACK = ImageManager.load("/textures/cards/back.png");
}

这个很好用。

还有这个:

public class Card{
    private Image image;

    public Card(){
        image = ImageManager.load("/textures/cards/back.png");
    }
}

导致IOException的结果。

有人能告诉我为什么会发生这种情况以及我该如何改变做事方式吗?

编辑:

我不确定为什么会出现这个异常,但我设法暂时修复了它。

我的程序结构是这样的:

public void run(){
    init();
        while(running){
            update();
            render();
        }
    finish();
}

我原计划在init方法中加载所有图片并创建所有实例。但只是为了测试我的加载方法,我快速创建了一个Card的实例。

但当我尝试加载图像时,它抛出了异常。从init()方法中加载图像解决了我的问题。

有人能告诉我为什么这会有如此大的区别吗?

顺便说一下,这是我的渲染方法。

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

    Graphics g = bs.getDrawGraphics();
    g.drawImage(background, 0, 0, null);

    // render actual game

    game.render(g);

    // ------------------

    g.dispose();
    bs.show();
}
  • 我将一个res文件夹添加到项目中,使得图片位于:~/res/textures/cards/back.png

3
图片:“/textures/cards/blue1.png”未找到! (“/textures/cards/back.png”); blue1.png != back.png,请解释。翻译:上述文字意思为,无法找到“/textures/cards/blue1.png”的图片文件。在代码中更改了文件路径,现在使用的是“/textures/cards/back.png”文件。请注意,“blue1.png”和“back.png”是两个不同的文件,不能混淆。 - ControlAltDel
/textures/cards/back.png 是否在你的类路径中?你正在加载类路径资源而不是文件。 - malaguna
@ControlAltDelete 这是我使用的两个纹理。我知道它们不一样,但结果是相同的错误。 - Jeroen Bos
是的,我已经将一个res文件夹添加到我的类路径中。该图像位于:~/res/textures/cards/back.png - Jeroen Bos
你使用的是Windows、Linux还是其他操作系统?你的路径大小写是否正确? - Guillaume F.
我刚刚尝试了一下(通过重新创建您未发布的代码),对我来说两种方式都可以正常工作。因此,要么是您的环境有些问题您没有告诉我们,要么是某种打字错误,或者可能是文件访问问题。为了获得更好的帮助,请创建一个完全可工作的MCVE,以显示出问题,并确保包括相关的环境信息(操作系统,JVM版本等)。 - Harald K
1个回答

1

ImageIO.read(URL)的Javadoc有些模糊,但似乎它会根据URL在内部缓存输入流,并且在多线程环境下的行为并不明显。

如果我是你,我会尝试使用ImageIO.read(InputStream)。

希望这可以帮到你。

祝好,

Slava Imeshev


ImageIO(或者说,ImageInputStream实现)缓存任何输入流的内容,以便能够向后查找,而不考虑输入。这种缓存是每个流(而不是每个URL)完全线程安全(从ImageIO.read(...)的角度来看)。然而,使用您建议的ImageIO.read(InputStream)方法可能有助于找到异常的原因(最可能的原因是资源不存在或不可读)。 - Harald K

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接