Java检查file.exists()是否与ImageIO.read(文件)不兼容

时间:2012-11-27 06:34:23

标签: java image file-io

我知道如何通过if / else检查文件是否存在,并且它在我之前的任务中有效:

File f = new File("file.txt");
    if (f.exists() && f.canRead()) {
        // Code goes here.
    } else { } // Error message.

但是,如果我对缓冲图像执行相同的操作,请执行以下操作:

private BufferedImage img;

File f = new File("pic.png");
    if (f.exists() && f.canRead()) {
        img = ImageIO.read(f);
    } else { } // Error message.

然后编译器需要try / catch或@throws来破坏目的。我究竟做错了什么?将所有精灵打包成一个.jar并将它们称为资源(我计划在完成后再做)会不会更好?

如果有任何问题,我在JRE 1.6上运行,文件检查在switch case语句中。

4 个答案:

答案 0 :(得分:2)

作为一个经过检查的例外,您必须抓住它。它实际上是否抛出并不重要。您的手动错误处理将无法处理所有情况。考虑您正在从网络驱动器读取,并且在读取时可能会中断连接。

更新查看上面的评论。据说你必须构建一个try / catch块,因为可以抛出异常并处理每个指定所需的已检查异常。通过先前的检查,您已经避免了FileNotFoundException的风险。有时你甚至让我对实现没有任何错误的地方进行了分类,但是在接口中你还需要处理它,例如ByteArryOutputStream.close()

答案 1 :(得分:2)

使用 try / catch块并不会破坏目的。

即使该文件存在且可读,也有很多其他异常可以抛出。

可能的例子:

  • 文件在被阅读时被删除
  • 文件的权限在被阅读时被撤销
  • 读取时已拔下/卸载磁盘驱动器

方法ImageIO.read()会抛出IOException

没有办法避免捕捉或抛弃它。

答案 2 :(得分:2)

  

我们已经与他详细讨论了这个问题,他说的是,如果我确切地知道将要发生什么,我应该尝试处理它而不诉诸尝试/捕获后退。

如果你的导师告诉你应该测试以避免IO异常,那么我担心他完全错了。

  1. 大多数I / O操作被声明为throw IOException,这是一个经过检查的异常。当您调用这些方法时,您的代码必须处理或传播异常。你没有选择。 Java语言要求对所有已检查的异常执行此操作。

  2. 测试所有可能的IOExceptions是不切实际的。例如,此代码可能会失败:

      if (f.exists() && f.canRead()) {
          os = new FileInputStream(f);
      }
    

    为什么呢?因为构造函数可能抛出IOException还有其他原因,例如硬盘错误,网络错误(如果文件位于远程安装的文件系统上),强制访问控制失败等等。除了尝试打开文件之外,通常无法以任何其他方式检测基础条件。

  3. 然后是竞争条件的问题。在上面的示例中,测试文件可读并尝试打开它之间有一个小的时间窗口。在该时间窗口中,可能某个其他线程或某个外部进程将删除该文件或更改其访问权限,以便打开将失败。无法关闭该时间窗口。

  4. 然后有一个问题,为什么你甚至想要来避免异常。我怀疑你的老师是“例外人”;也就是那些把“例外只应用于特殊事物”的建议中的一个人提到不合逻辑的极端。

    “异常只应用于特殊事物”建议基本上是说你不应该过度使用异常,因为它们有点贵。但昂贵是相对的。

    在此示例中,对File.exists()File.canRead()的调用也很昂贵,因为它们都需要进行系统调用,这将花费数千个时钟周期。更糟糕的是,除非您的应用程序有一些不寻常的事情,否则这两个测试将会成功...所以您刚刚完成了两次不必要的系统调用,以避免无论如何都不会抛出异常。除非这些测试失败的概率很高(即> 50%),否则跳过测试更高效,尝试打开并处理异常(如果发生)。


      

    我不会这样标记我的教授。我们没有具体谈论I / O的复杂性,它更多地是在一般的术语中,如果我可以避免它,我应该避免它。我不知道(并且他没有详细说明)有一些非常不可避免的异常。

    行。所以你的教授没有这么说。对他有好处。

    是的,他们在某种意义上不可避免地

      

    至于拒绝使用.exists()检查,性能是否显着?

    是。见这 - Syscall overhead

    或者,如果你不相信,那就写一个微基准并测量它。并将其与投掷和捕获异常的开销进行比较。

      

    是否会出现桌面版移动版等问题?

    不。或者当然不适用于操作系统使用虚拟内存来阻止一个“app”干扰另一个“app”的移动设备。

      

    对于故障排除/调试(如果我能够更好地查明问题,同时避免崩溃程序)的清晰度是否值得呢?

    好吧,我认为这段代码:

    try (InputStream is = new FileInputStream(f)) {
        // use file
    } catch (IOException ex) {
        System.err.println("IO error: ": ex.getMessage());
    }
    

    ...比这更简单,更容易维护和调试:

    if (!f.exists()) {
        System.err.println("File " + f + " does not exist");
    } else if (!f.isDirectory()) {
        System.err.println("File " + f + " is a directory");
    } else if (!f.canRead()) {
        System.err.println("File " + f + " is not readable");
    } ...
    } else {
        try (InputStream is = new FileInputStream(f)) {
            // read
        } catch (IOException ex) {
            System.err.println("IO error: "+ ex.getMessage());
        }
    }
    
    你不同意吗?

答案 3 :(得分:1)

如果您看到ImageIO.read方法的声明: -

public static BufferedImage read(File input)
                          throws IOException

它声明要抛出IOException,这是CheckedException。因此,在调用该方法时,您需要在try-catch block中处理它。或者,声明它将在您使用它的方法中抛出: -

File f = new File("pic.png");
if (f.exists() && f.canRead()) {
    try {
        img = ImageIO.read(f);
    } catch (IOException e) {
        e.printStackTrace();
    }
} else { } // Error message.

但是,如果您没有像上面那样处理它,那么您必须在方法的throws子句中声明该方法,以便将其传播到caller,所以它处理它。

通常,任何已检查的异常都应该被处理或传播给调用者,后者逐渐达到main方法,在这种情况下,如果main方法不处理它,则由JVM,导致您的计划终止。

通常,在抛出它的方法本身中处理异常是个好主意,并在需要时将相应的消息返回给调用者。