Java中IO异常的处理

Java中IO异常的处理,java,exception,exception-handling,io,resource-management,Java,Exception,Exception Handling,Io,Resource Management,基本上,我想打开一个文件,读取一些字节,然后关闭文件。这就是我想到的: try { InputStream inputStream = new BufferedInputStream(new FileInputStream(file)); try { // ... inputStream.read(buffer); // ... } catch (IOException e) { //

基本上,我想打开一个文件,读取一些字节,然后关闭文件。这就是我想到的:

try
{
    InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
    try
    {
        // ...
        inputStream.read(buffer);
        // ...
    }
    catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    finally
    {
        try
        {
            inputStream.close();
        }
        catch (IOException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
catch (FileNotFoundException e)
{
    // TODO Auto-generated catch block
    e.printStackTrace();
}

也许我被RAII宠坏了,但在Java中一定有更好的方法来实现这一点,对吧?

我不知道这是否是正确的方法,但您可以将所有代码放在同一个try块中,然后依次使用不同的catch块

try {
  ...
}
catch (SomeException e) {
  ...
}
catch (OtherException e) {
  ...
}

如果您想在纯Java中实现这一点,那么您发布的代码看起来还可以

您可以使用第三方库,如Commons IO,在其中您需要编写的代码要少得多。e、 g

查看Commons IO,网址为:


如果您对
IOException
FileNotFoundException
具有相同的异常处理代码,那么您可以用一个
catch
子句以更简洁的方式重写示例:

try {
    InputStream input = new BufferedInputStream(new FileInputStream(file));
    try {
        // ...
        input.read(buffer);
        // ...
    }
    finally {
        input.close();
    }
}
catch (IOException e) {
    e.printStackTrace();
}
如果您可以传播异常(这可能比手动打印堆栈跟踪更有意义),那么您甚至可以摆脱外部
try catch
。如果您在程序中没有捕获到一些异常,您将自动打印堆栈跟踪

另外,手动关闭流的需要也将在Java7中解决

通过自动资源管理和异常传播,代码简化为以下内容:

try (InputStream input = new BufferedInputStream(new FileInputStream(file))) {
    // ...
    input.read(buffer);
    // ...
}
try
{
    InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
    byte[] buffer = new byte[1024];
    try
    {
        // ...
        int bytesRead = 0;
        while ((bytesRead = inputStream.read(buffer)) != -1) {                
           //Process the chunk of bytes read
        }
    }
    catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    finally
    {           
        inputStream.close();
    }
}
catch (FileNotFoundException e)
{
    // TODO Auto-generated catch block
    e.printStackTrace();
}
public void foo(String name) throws IOException {
    InputStream in = null;
    try {
        in = new FileInputStream(name);
        in.read();
        // whatever
    } finally {
        if(in != null) {
            in.close();
        }
    }
}

使用org.apache.commons.io.FileUtils.readFileToByteArray(文件)或该软件包中的类似内容。它仍然会抛出IOException,但会为您进行清理。

请尝试以下操作:

try (InputStream input = new BufferedInputStream(new FileInputStream(file))) {
    // ...
    input.read(buffer);
    // ...
}
try
{
    InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
    byte[] buffer = new byte[1024];
    try
    {
        // ...
        int bytesRead = 0;
        while ((bytesRead = inputStream.read(buffer)) != -1) {                
           //Process the chunk of bytes read
        }
    }
    catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    finally
    {           
        inputStream.close();
    }
}
catch (FileNotFoundException e)
{
    // TODO Auto-generated catch block
    e.printStackTrace();
}
public void foo(String name) throws IOException {
    InputStream in = null;
    try {
        in = new FileInputStream(name);
        in.read();
        // whatever
    } finally {
        if(in != null) {
            in.close();
        }
    }
}

谷歌番石榴(GoogleGuava)试图通过引入新技术来解决这个问题


否则,您必须等到JDK 7出现,因为它解决了引发IOException的一些情况。

通常这些方法都封装在库中。除非您想在这个级别上编写,否则最好创建自己的助手方法或使用现有的方法,如


有时,您可以将代码简化为以下内容:

try (InputStream input = new BufferedInputStream(new FileInputStream(file))) {
    // ...
    input.read(buffer);
    // ...
}
try
{
    InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
    byte[] buffer = new byte[1024];
    try
    {
        // ...
        int bytesRead = 0;
        while ((bytesRead = inputStream.read(buffer)) != -1) {                
           //Process the chunk of bytes read
        }
    }
    catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    finally
    {           
        inputStream.close();
    }
}
catch (FileNotFoundException e)
{
    // TODO Auto-generated catch block
    e.printStackTrace();
}
public void foo(String name) throws IOException {
    InputStream in = null;
    try {
        in = new FileInputStream(name);
        in.read();
        // whatever
    } finally {
        if(in != null) {
            in.close();
        }
    }
}

当然,这意味着
foo
的调用者必须处理
IOException
,但大多数情况下都应该是这样。最终,您并没有真正降低那么多的复杂性,但由于嵌套的异常处理程序更少,代码变得更可读。

我在不使用实用程序的情况下对此的看法是:

InputStream inputStream = null;
try {
    inputStream = new BufferedInputStream(new FileInputStream(file));
    // ...
    inputStream.read(buffer);
    // ...
} catch (IOException e) {
    e.printStackTrace();
    throw e; // Rethrow if you cannot handle the exception
} finally {
    if (inputStream != null) {
        inputStream.close();
    }
}
//...
buffer = FileUtils.readFileToByteArray(file);
//...
不是一行,但也不是很糟糕。使用Apache Commons IO,比如说:

InputStream inputStream = null;
try {
    inputStream = new BufferedInputStream(new FileInputStream(file));
    // ...
    inputStream.read(buffer);
    // ...
} catch (IOException e) {
    e.printStackTrace();
    throw e; // Rethrow if you cannot handle the exception
} finally {
    if (inputStream != null) {
        inputStream.close();
    }
}
//...
buffer = FileUtils.readFileToByteArray(file);
//...

需要记住的是,标准Java缺少许多这些小实用程序和每个人都需要的易于使用的接口,因此您必须依赖一些支持库,例如。。。在您的项目中,(或实现您自己的实用程序类)。

@Vash:我真不敢相信我需要那么多样板代码和嵌套的try/catch块来执行这么简单的任务。@Heandel,@Vash:我在该示例中计算了21行代码,不包括注释。他想做的就是“打开文件,读取数据,关闭文件。如果发生错误,仍然关闭文件,但也打印异常信息”。这应该是3,也许4行代码。如果您需要询问代码是如何变得更好的,那么您确实需要开始学习Java以外的其他语言。@Vash:不,在某些语言中,这种操作不需要这么多try/catch块,这与编译器强制您处理异常无关。正如我之前所说,你需要开始学习其他一些语言。睁开你的眼睛。因为使用一种残废的语言而被迫编写难看的代码已经够糟糕的了,但对于程序员来说,甚至没有意识到可能存在更好的解决方案是不可原谅的。伙计们,用任何语言编写难看的代码都是可能的,不仅仅是Java。这个例子之所以笨重,是因为它是这样写的。通过传播异常,甚至可以去掉所有的
catch
子句。当然,如果要正确地关闭文件,就不能去掉
finally
子句。然而,从我的观点来看,这是一个小小的不便,正如我在回答中提到的,Java7将解决这个问题。在C++中,自动资源管理不像java那样有用,主要原因是GC。我主要使用C++ BTW,所以我不是java倡导者。@ VAS:再一次,不,其他语言确实有解决方案,它提供了适当的健壮的资源管理,而不必编写一个TIG/catch。C++可以做到这一点。想要打印出异常信息可能需要一个try/catch块,但仅用于打印。打开、读取和关闭文件都可以通过完美的错误处理来完成,无需编写一个try-catch,当然也无需使用
finally
。因此,在其第七个版本中,即第一个版本发布15年后,Java将最终(无双关语)提供它创建时要改进的语言的主要功能之一。我没有印象。@sbi:而且它仍然没有提供相同的功能,而只是满足于删除一些样板代码。Java7的资源管理更像是C#的使用,而不是C++的RAII。比他们现在拥有的要好得多,但仍然不如你所说的,它打算改进的语言的主要特点。哦,不!我的答案是被C++的拥护者劫持。是 啊真有趣。对于这类问题,[……]通常会导致对抗和争论,问题可以关闭。当然不会,因为它突出了一个有效点。只是说…@JavaDeveloper如果FileInputStream ctor抛出异常,它应该释放资源,BufferedInputStream不会抛出任何东西(请参阅)。所以它不应该泄露资源。